python的设计原则及设计模式
七大设计原则
单一职责原则
【SINGLE RESPONSIBILITY PRINCIPLE】
一个类负责一项职责。
里氏替换原则
【LISKOV SUBSTITUTION PRINCIPLE】
继承与派生的规则。(子类可替换父类)
依赖倒转原则
【DEPENDENCE INVERSION PRINCIPLE】
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程。
接口隔离原则
【INTERFACE SEGREGATION PRINCIPLE】
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。
迪米特法则
【LOW OF DEMETER】
高内聚 低耦合 – high cohesion low coupling
开闭原则
【OPEN CLOSE PRINCIPLE】
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
组合/聚合复用原则
【Composition/Aggregation Reuse Principle(CARP) 】
尽量使用组合和聚合少使用继承的关系来达到复用的原则。
24种设计模式
创建型模式
工厂模式
【Factory method pattern】
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
例子:
1、 我们有一个基类Person ,包涵获取名字,性别的方法 。有两个子类male 和female,可以打招呼。还有一个工厂类。
2、 工厂类有一个方法名getPerson有两个输入参数,名字和性别。
3、 用户使用工厂类,通过调用getPerson方法。
在程序运行期间,用户传递性别给工厂,工厂创建一个与性别有关的对象。因此工厂类在运行期,决定了哪个对象应该被创建。
classPerson:def __init__(self):
self.name=None
self.gender=NonedefgetName(self):returnself.namedefgetGender(self):returnself.genderclassMale(Person):def __init__(self, name):print "Hello Mr." +nameclassFemale(Person):def __init__(self, name):print "Hello Miss." +nameclassFactory:defgetPerson(self, name, gender):if gender == ‘M':
returnMale(name)if gender == 'F':returnFemale(name)if __name__ == '__main__':
factory=Factory()
person= factory.getPerson("Chetan", "M")
抽象工厂模式
【Abstract factory pattern】
提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类。
importrandomclassPetShop(object):def __init__(self,animal_factory=None):#pet 宠物 factory 工厂
self.pet_factory =animal_factorydefshow_pet(self):
pet=self.pet_factory.get_pet()print("this is a lovely", pet)print("it says",pet.speak())print("it eats",self.pet_factory.get_food())classDog:defspeak(self):return "Dog"
def __str__(self):return "this is Dog"
classCat:defspeak(self):return "Cat"
def __str__(self):return "this is Cat"
classCatFactory:defget_pet(self):returnCat()defget_food(self):return "cat food"
classDogFactory:defget_pet(self):returnDog()defget_food(self):return "dog food"
defget_factory():returnrandom.choice([DogFactory,CatFactory])if __name__ == '__main__':
shop= PetShop() #pet_factory 默认为None,后面延迟加载
shop.pet_factory= get_factory()() #延迟加载,随机选择一个工厂然后实例出来一个对象给商店
shop.show_pet()
生成器模式(建造者模式)
【Builder pattern】
使用生成器模式封装一个产品的构造过程,并允许按步骤构造。将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
class Director: #director 监视
def __init__(self):
self.builder= None #builder建造者
defconstruct_building(self):
self.builder.new_building()
self.builder.build_floor()
self.builder.build_size()defget_building(self):returnself.builder.buildingclassBuilder:def __init__(self):
self.building=Nonedefnew_building(self):
self.building=Building()classBuilding:def __init__(self):
self.floor=None
self.size=Nonedef __repr__(self): #和__str__ 魔法方法类似,都是打印对象的时候调用,不过repr更强大
#repr方法在交互式环境下也能起作用,即交互式环境直接输变量名打印的时候
#__str__ 只有在print的时候才会触发
return "Floor:%s | Size: %s" %(self.floor,self.size)classBuilderHouse(Builder):defbuild_floor(self):
self.building.floor= "One"
defbuild_size(self):
self.building.size= "Big"
class BuilderFlat(Builder): #flat 公寓
defbuild_floor(self):
self.building.floor= "More than One"
defbuild_size(self):
self.building.size= "small"
if __name__ == '__main__':
director=Director()
director.builder=BuilderHouse()
director.construct_building()
building=director.get_building()print(building)
director.builder=BuilderFlat()
director.construct_building()
building=director.get_building()print(building)
原型模式
【Prototype pattern】
当创建给定类的实例过程很昂贵或很复杂时,就使用原形模式。
单例模式
【Singleton pattern】
确保一个类只有一个实例,并提供全局访问点。
classA(object):__obj =False__init =Falsedef __init__(self, name):if not A.__init:
self.name=name
A.__init =Truedef __new__(cls, *args, **kwargs):if not A.__obj:
A.__obj = super().__new__(cls)return A.__obj
if __name__ == '__main__':#只初始化一次的单例模式
a = A("nick")
b= A("nick2")print(a.name) #nick
print(b.name) #nick
print(a == b) #True
print(id(a), id(b)) #54527760 54527760
多例模式
【Multition pattern】
在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题。
结构型模式
适配器模式
【Adapter pattern】
将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。对象适配器使用组合,类适配器使用多重继承。
importosclassDog:def __init__(self):
self.name="Dog"
def bark(self): #bark :叫声
return "woof!" #woof 低吠声
classCat:def __init__(self):
self.name= "Cat"
def meow(self): #meow 猫叫声
return "meow" #meow 猫叫声
classHuman:def __init__(self):
self.name= "Human"
defspeak(self):return "hello, python"
classCar:def __init__(self):
self.name= "Car"
defmake_noise(self, noise_level):return "noise level is {}".format(noise_level)class Adapter: #adapter 适配器
def __init__(self,obj,adapted_methods): #adpted 适应
self.obj =obj
self.__dict__.update(adapted_methods) #self.__dict__是打印对象所有的属性,结果是一个字典 {"kye":value}
#key对应对象的属性,value对应属性的属性值。这里就相当于把不同类的方法都绑定到Adapter这个类实例化出来的
#对象的make_noise 属性上面去,该属性的值对应其他类里面的方法。
def __getattr__(self, attr): #当调用类不存的属性或者方法时,就会触发该魔法方法
return getattr(self.obj, attr) #getattr(object,attr [,default])
defmain():
objects=[]
dog=Dog()
objects.append(Adapter(dog,dict(make_noise=dog.bark)))
cat=Cat()
objects.append(Adapter(cat,dict(make_noise=cat.meow)))
human=Human()
objects.append(Adapter(human,dict(make_noise=human.speak)))
car=Car()
car_noise= lambda : car.make_noise(3)
objects.append(Adapter(car,dict(make_noise=car_noise)))for obj inobjects:print("A",obj.name,"goes",obj.make_noise()) #这里 obj.make_noise 就相当于 dog.bark 这些方法,后面加括号代表执行
print(obj.obj) #原来的对象被存储到obj属性里面.
if __name__ == '__main__':#适配器模式在不改变原有类的基础上,统一了所有的方法,还能够保存原有对象的引用obj属性
main()
桥接模式
【Bridge pattern】
使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变。
classDrawingAPI1:defdraw_circle(self, x, y, radius):print("API1.circle at {} : {} ,radius:{}".format(x, y, radius))classDrawingAPI2:defdraw_circle(self,x,y,radius):print("API2.cirle at {} : {} ,radius:{}".format(x, y, radius))classCircleShape:def __init__(self,x,y,radius,drawing_api):
self._x=x
self._y=y
self._radius=radius
self._drawing_api=drawing_apidefdraw(self):
self._drawing_api.draw_circle(self._x,self._y,self._radius)def scale(self,pct): #scale 规模
self._radius *= pct #pct 百分比
defmain():
shapes=(
CircleShape(1,2,3,DrawingAPI1()),
CircleShape(5,7,11,DrawingAPI2()),
)#提供2个
for shape inshapes:
shape.scale(2.5)
shape.draw()if __name__ == '__main__':#桥接模式就是一个类的属性的值是另一个类的实例对象。然后可以通过这个类的实例对象去调用另外一个类对象的方法
main()
组合模式
【Composite pattern】
允许你将对象组合成树形结构来表现‘整体/部分’层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
装饰器模式
【Decorator pattern】
动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
classfoo(object):deff1(self):print("func f1")deff2(self):print("func f2")classfoo_decorator(object):def __init__(self,decorator):
self._decorator=decoratordeff1(self):print("decorator f1")
self._decorator.f1()def __getattr__(self, item):#当得不到想要的属性时,就去自己的装饰里面拿,使用 getattr()内建方法
returngetattr(self._decorator,item)if __name__ == '__main__':#主要思想还是使用魔法方法 __getattr__ 方法, 然后把另外一个对象赋值到自身的属性上面.
#添加一个运行另外一个对象的接口,没有接口时,就去直接调用另一个对象的方法.
u =foo()
d=foo_decorator(u)
d.f1()
d.f2()
外观模式
【Facade pattern】
提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
classsmall_or_piece1:def __init__(self):pass
defdo_small1(self):print('do small 1')classsmall_or_piece_2:def __init__(self):pass
defdo_small2(self):print('do small 2')classsmall_or_piece_3:def __init__(self):pass
defdo_small3(self):print('do small 3')classoutside:def __init__(self):
self.__small1 =small_or_piece1()
self.__small2 =small_or_piece_2()
self.__small3 =small_or_piece_3()defmethod1(self):
self.__small1.do_small1() ##如果这里调用的不只2两函数,作用就显示出来了,可以把原本复杂的函数调用关系清楚化,统一化
self.__small2.do_small2()defmethod2(self):
self.__small2.do_small2()
self.__small3.do_small3()if __name__ == '__main__':#外观模式应用于在很多复杂而小功能需要调用时,并且这些调用还具有一定的相关性,即一调用就是一系列的调用.
osd =outside()
osd.method1()
osd.method2()
亨元模式
【Flyweight Pattern】
如想让某个类的一个实例能用来提供许多‘虚拟实例’,就使用蝇量模式。
代理模式
【Proxy pattern】
为另一个对象提供一个替身或占位符以控制对这个对象的访问。
行为型模式
解释器模式
【Interpreter pattern】
使用解释器模式为语言创建解释器。
模板方法模式
【Template pattern】
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
责任链模式
【Chain of responsibility pattern】
通过责任链模式,你可以为某个请求创建一个对象链。每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。
classHandler:def __init__(self):
self.successor=Nonedef add_successor(self,successor): #successor 后续的事,继承者
self.successor =successorclassConcreteHandler1(Handler):defhandle(self,request):if request>0 and request<=10:print("concreteHandler1 deal %s"%request)elif self.successor is notNone:
self.successor.handle(request)else:print("no handler can deal with %s"%request)classConcreteHandler2(Handler):defhandle(self,request):if request>10 and request<=20:print("ConcreteHandler2 deal %s"%request)elif self.successor is notNone:
self.successor.handle(request)else:print("no handler can deal with %s" %request)classConcreteHandler3(Handler):defhandle(self,request):if request>20 and request<=30:print("ConcreteHandler3 deal %s"%request)elif self.successor is notNone:
self.successor.handle(request)else:print("no handler can deal with %s" %request)if __name__ == '__main__':
h1= ConcreteHandler1() #创建处理者1
h2 = ConcreteHandler2() #创建处理者2
h3 = ConcreteHandler3() #创建处理者3
h1.add_successor(h2) #添加h1如果处理不了就让h2去处理
h2.add_successor(h3) #如果h2处理不了就让h3去处理
requests = [1,3,23,42,34,67,11,22,14,36]for request inrequests:
h1.handle(request)
命令模式
【Command pattern】
将”请求”封闭成对象,以便使用不同的请求,队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
importosclassMoveFileCommand(object):def __init__(self,src,dest):
self.src=src
self.dest=destdefexecute(self):
self()#直接调用对象本身会执行__call__方法
def __call__(self, *args, **kwargs): #__call__ 魔法方法直接调用对象的时候执行的方法
print("renaming {} to {}".format(self.src,self.dest))
os.rename(self.src,self.dest)defundo(self):print("renaming {} to {}".format(self.dest,self.src))
os.rename(self.dest,self.src)if __name__ == '__main__':
command_stack=[]
command_stack.append(MoveFileCommand("foo.txt","bar.txt"))
command_stack.append(MoveFileCommand("bar.txt","foo.txt"))for cmd incommand_stack:
cmd.execute()for cmd inreversed(command_stack):
cmd.undo()
迭代器模式
【Iterator pattern】
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
中介者模式
【Mediator pattern】
使用中介者模式来集中相关对象之间复杂的沟通和控制方式。
备忘录模式
【Memento pattern】
当你需要让对象返回之前的状态时(例如,你的用户请求‘撤销’), 你使用备忘录模式。
观察者模式
【Observer pattern】
在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
状态模式
【State pattern】
允许对象在内部状态改变时改变它的行为,对象看起来好象改了它的类。
策略模式
【Strategy pattern】
定义了算法族,分别封闭起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
访问者模式
【Visitor pattern】
当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式。