设计模式与面向对象
一、设计模式
设计模式:对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。
每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。
设计模式的创始人,一般称为“四人帮”(Gang of Four, GoF):Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides......他们编写一套书来介绍23种设计模式:《设计模式:可复用面向对象软件的基础》。
二、面向对象回顾
设计模式是用来设计面向对象系统中的设计。不解决面向过程的问题。
1、面向对象的三大特性
封装:把数据和函数封装到一个类里,体现类内和类外。
继承:由于有了封装,需要通过继承在类之间复用代码。
多态:python本身是一门多态语言,因此不需去处理多态的问题。Java中则会区分虚类和普通类。
因此这三个特性是一个递进的关系。
2、接口
接口:若干抽象方法的集合。
作用:限制实现接口类必须按照接口给定的调用方式实现这些方法;对高层模块隐藏了类的内部实现。
# 方法一:继承 # 存在的问题是:如果不调用pay方法并不会报错 class Payment: def pay(self, money): raise NotImplementedError class Alipay(Payment): pass class WechatPay(Payment): pass p = Alipay() p.pay(100) # 方法二:抽象类 # 约束子类必须实现抽象类:TypeError: Can't instantiate abstract class Alipay with abstract methods pay from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # abstract class @abstractmethod def pay(self, money): # 抽象方法 pass class Alipay(Payment): def pay(self, money): # 实现Payment接口 print('支付宝支付%d元' % money) class WechatPay(Payment): def pay(self, money): # 实现Payment接口 print("微信支付%d元" % money) p = Alipay() p.pay(100)
不用去查看具体实现,只要去查看接口(抽象类)的结构和注释,就可以了解需要传递的参数和pay方法的使用。
在写底层模块或者开源框架时需要大量应用设计模式,优化封装,让程序员在学习和使用时非常方便。
三、面向对象设计SOLID原则
不管是面向对象设计还是各个设计模式都需要遵循这五大原则。
- 开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
- 里氏替换原则:所有引用父类的地方必须能透明地使用其子类的对象。(子类是特殊的父类,子类继承父类时同样方法的表现一致)
# 子类和父类的show_name内部实现和逻辑可能不同,但是参数和返回值是相同的 class User: def show_name(self): pass class VIPUser(User): def show_name(self): pass def show_user(u): # u可以是普通用户或VIP res = u.show_name()
- 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 抽象 # abstract class @abstractmethod def pay(self, money): # 抽象方法 pass class Alipay(Payment): # 细节 def pay(self, money): # 实现Payment接口 print('支付宝支付%d元' % money) class WechatPay(Payment): # 细节 def pay(self, money): # 实现Payment接口 print("微信支付%d元" % money)
- 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
from abc import ABCMeta, abstractmethod # (一)单一总接口的情况 # 子类必须实现所有抽象方法,但其实很多方法是子类不需要的 class Animal(metaclass=ABCMeta): @abstractmethod def walk(self): pass @abstractmethod def swim(self): pass @abstractmethod def fly(self): pass class Tiger(Animal): # Class Tiger must implement all abstract methods def walk(self): print("老虎走路") # (二)多个接口隔离情况 class LandAnimal(metaclass=ABCMeta): @abstractmethod def walk(self): pass class WaterAnimal(metaclass=ABCMeta): @abstractmethod def swim(self): pass class SkyAnimal(metaclass=ABCMeta): @abstractmethod def fly(self): pass class Tiger(LandAnimal): def walk(self): print("老虎走路") class Frag(LandAnimal,WaterAnimal): # 青蛙多继承 pass
- 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
四、设计模式分类
1、创建型模式(5种)
主要聚焦怎么去创建对象。目的是为了隐藏底层模块的逻辑。
工厂方法模式、抽象工厂模式、创建者模式、原型模式、单例模式。
2、结构型模式(7种)
主要关注在几个类之间怎么组合协同工作在一起。
适配器模式、桥模式、组合模式、装饰模式、外观模式、享元模式、代理模式。
3、行为型模式(11种)
主要关注方法和行为的完成。
解释器模式、责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、访问者模式、模板方法模式。
五、设计模式总结
python这门语言是一个动态语言,对参数、父类子类等限制不严格。对设计模式并不强求,不是完全契合,而java则是完全与设计模式契合。但是了解一些设计模式对写出优秀代码还是非常有帮助的。
在写大型项目时,尤其是底层代码、开源框架等时,设计模式的优势将更加突出。