设计模式-原型模式

发布在 设计模式

原型模式(Prototype Pattern):使用原型实例创建指定创建对象的种类,并通过拷贝这些原型创建新对象。这个模式很好理解,就是ctrl+c,ctrl+v后做一些小修改。

这里面涉及一个知识点就是深拷贝和浅拷贝的问题,但我相信任何python开发人员都知道copy()deepcopy()的区别,这里就不多说了(有兴趣的可以去看python中这2个函数的实现)。

个人理解当需要多个类对象时,如果要进行很多复杂的、消耗时间的初始化操作,而这些对象之间又仅有少量不同时,可以考虑使用原型模式。

阅读全文

建造者模式(Builder Pattern):将复杂对象的创建和表示分离,使同样的构建过程可以创建不同的表示。

进一步说,建造者隐藏了产品是如何组装的,使建造代码和表示代码分离。建造对象时 构件顺序稳定 的情况下,不管每一步具体怎么变都可以适用。

简单说,建造者模式将需要一系列动作才能完成的事固化下来,并定义了一个Director给客户端使用。还是很抽象的话,想想如何把大象装进冰箱:

  1. 打开冰箱门
  2. 把大象装进去
  3. 关上冰箱门

这个步骤比较简单,但如果细化一下:买冰箱、接通电源、买大象、清洗大象……很可能就会有300个步骤。建造者模式则提供了一系列行为的集合,保证以后有把山羊装进冰箱这样的需求时候不会遗漏某个步骤(想想KFC、麦当劳生产食品的步骤,其实是建造者模式不错的例子)。

阅读全文

设计模式-工厂模式

发布在 设计模式

工厂模式又可以分为工厂方法模式和抽象工厂模式。

工厂方法模式(Factory Method Pattern)

工厂模式是指:定义一个接口用户创建对象,让子类决定实例化哪一个类。

工厂模式中存在4个角色:

  1. 抽象工厂
  2. 具体工厂
  3. 抽象产品
  4. 具体产品

抽象工厂产生抽象产品,具体工厂生产具体产品。 这句话很重要,理解了这句话就理解了工厂方法模式。

阅读全文

设计模式-总览

发布在 设计模式

很久很久以前,忘记从哪看到一句话——设计模式是对编程语言缺陷的弥补。

年轻的我并没意识到这句话背后的真实含义以及所处语境,外加之后主要开发语言是Python这个动态语言,设计模式真的没怎么用到——比如装饰模式不就是Python中的装饰器嘛,一个语法糖能解决的事居然还弄出个模式来?

直到我开始学习openstack的源码,发现里面用到了大量的设计模式,才明白自己是多么无知可笑。

这里借用一位大佬的话:

如果你觉得设计模式在某程度上没用,说明两个问题:
1.你的系统还不足以复杂到要用设计模式的程度
2.你的经验还没强到能熟练应用设计模式的程度。

能找到这篇文章的,应该都知道面向过程、面向对象、封装继承多态、高内聚低耦合(包含程序级别以及架构级别)、开闭原则(对扩展开放、对修改关闭)、依赖倒置原则(尽量使用抽象类型作为对象实例变量类型,用于实现开闭原则)、单一责任原则(一个模块只负责一个功能)等一堆的名词,以及“组合优于继承”(这里略有争议,我个人对此赞同,最近看一些继承过多的代码总是要向上找好几层父类,还要仔细看子类中有没有重写父类方法,术语叫做类膨胀)。

阅读全文

上次学习了Nova创建虚拟机的过程,这次来看一下Glance是如何上传镜像的。相比于Nova,Glance源码使用了大量的代理模式和装饰器模式,阅读代码时候一个不仔细就会一脸懵X。根据上次说的Openstack套路,我们通过setup.cfg直奔主题——glance/cmd/api.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def main():
try:
config.parse_args()
config.set_config_defaults()
wsgi.set_eventlet_hub()
logging.setup(CONF, 'glance')
notifier.set_defaults()
if cfg.CONF.profiler.enabled:
_notifier = osprofiler.notifier.create("Messaging",
oslo_messaging, {},
notifier.get_transport(),
"glance", "api",
cfg.CONF.bind_host)
osprofiler.notifier.set(_notifier)
osprofiler.web.enable(cfg.CONF.profiler.hmac_keys)
else:
osprofiler.web.disable()
server = wsgi.Server(initialize_glance_store=True)
server.start(config.load_paste_app('glance-api'), default_port=9292)
server.wait()
except KNOWN_EXCEPTIONS as e:
print(e)
fail(e)
阅读全文

作为已经比较成熟的IAAS开源解决方案,OpenStack已经发布了19个版本,目前稳定版是Stein,并且下一个版本Train也预计在10月发布。可以说,从代码架构角度来说对于初学者来说已经略微复杂,但最核心的组件有以下几个:

  1. Nova:负责虚拟机相关。
  2. Glance:负责镜像相关。
  3. Cinder:负责存储相关。
  4. Neutron:负责网络相关。
  5. Keystone:负责鉴权以及服务注册。

大体架构如下图:

all.png

阅读全文

能看到这篇文章的小伙伴肯定已经知道什么是Scrapy以及Scrapy-Redis了,基础概念这里就不再介绍。默认情况下Scrapy-Redis是发送GET请求获取数据的,对于某些使用POST请求的情况需要重写make_request_from_data函数即可,但奇怪的是居然没在网上搜到简洁明了的答案,或许是太简单了?

这里我以httpbin.org这个网站为例,首先在settings.py中添加所需配置,这里需要根据实际情况进行修改:

1
2
3
4
5
SCHEDULER = "scrapy_redis.scheduler.Scheduler"  #启用Redis调度存储请求队列
SCHEDULER_PERSIST = True #不清除Redis队列、这样可以暂停/恢复 爬取
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" #确保所有的爬虫通过Redis去重
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'
REDIS_URL = "redis://127.0.0.1:6379"

阅读全文

原文,文章作者也是《Hands-On Dependency Injection in Go》的作者,向原作者表示感谢。


你是否曾经由于添加某个新功能却导致另一个功能出问题?修复好这个,另一个又出问题,就好象打地鼠一般。

你是否曾经花费大量的时间调试Bug,最后却发现问题潜伏在另一个、甚至毫不相关的模块中?

这些问题都是由于高耦合引起的。

在这篇文章中,我们来使用解偶的方式来让代码更加易于理解、维护、测试。

阅读全文

go get命令使用socket代理

发布在 Golang

由于某些不可描述的原因,国内使用go get命令安装某些包的时候会超时导致失败,比如net包、sys包、tools包等。第一种解决办法就是自己从git上下载后添加链接到GOPATH中,比如:

1
2
3
4
5
6
7
8
9
git clone https://github.com/golang/net.git $GOPATH/src/github.com/golang/net

git clone https://github.com/golang/sys.git $GOPATH/src/github.com/golang/sys

git clone https://github.com/golang/tools.git $GOPATH/src/github.com/golang/tools

ln -s $GOPATH/src/github.com/golang $GOPATH/src/golang.org/

cd $GOPATH/src/golang.org/ && mv golang x

阅读全文
作者的图片

Roy

君以国士待我,我必以国士报君。


野生程序猿


China