前言
一些开源的第三方库、框架中大量采用设计模式设计底层代码,使得框架的使用者,可以更加简单、舒服地调用底层代码进行高层代码的开发;
这就是设计模式的魅力所在;
软件开发流程大致分为以下3大流程
- 需求分析
- 程序分析和设计
- 程序开发
设计模式本质是针对面向对象编程,在程序设计阶段应当遵守的设计原则。
什么是好用的代码呢?其实就是代码质量比较高,如何评价代码质量的高低呢?最常用的、最重要的评价标准,就是代码的
遵守这些设计原则,有利于设计出更加松耦合、易于扩展、易于高层代码调用的程序;
一、设计模式概念
设计模式(Design Pattern)是前辈们经过相当长的一段时间的试验和错误总结出来的,是软件开发过程中面临的通用问题的解决方案。
这些解决方案使用设计模式是为了提高代码的
- 可维护性
- 可读性
- 可扩展性
- 灵活性
- 简洁性
- 可复用性
- 可测试性
每1个设计模式系统地命名、解释和评价了面向对象系统中1个重要的反复出现的设计。
二、面向对象
上文提到设计模式是针对面向对象程序提出的程序设计方案,所以回顾下面向对象知识。
1.面向对象的3大特性
面向对象的3大特性不是1个平级并列的关系而是1个循序递进的关系
封装
把属性(数据)、方法(函数)封装到1个类里面
继承
通过继承可以解决2个类之间复用代码的问题
多态
Python本身是1本多态的语言
2.面向对象的接口
在面向对象编程中我们经常使用接口
接口概念
接口是若干抽象方法的集合
接口作用
规范、限制实现类的方法
对高层代码(Client)隐藏了类的内部实现
降低高层代码(Client)调用底层代码的复杂度(Client底层代码的调用者不需要关心底层代码是怎么实现的,达到目的即可)
三、面向对象设计原则
SOLID原则指:面向对象编程需要遵循的5大原则
5大原则英文首字母拼成Solid单词;
1.单一职责(Single Responsibility Principle)
不要存在 >1个导致类变更的原因,一旦上层代码修改,只能有1个理由去修改底层代码的1个类代码。
既1个类负责1项职责。
不能把不同类型的代码都集中在1个类里面,这样设计一旦高层代码修改,就大大提高了这个类的代码修改风险;
2.开放封闭原则(Open Close Principle)
1个软件实体(如类、模块、函数)应该对扩展开放,对修改关闭。
既软件扩展新功能时应尽量不修改原代码。
3.里氏替换原则(Liskov Substitution Principle)
所有引用父类的地方必须能透明地使用其子类对象;
即在调用1个类的方法时,这个方法的参数,可以是1个父类的对象,也可以是继承了这个父类的子类的对象;
这就需要子类在重写方法和父类的方法时,实现的行为应当和父类方法保持一致;
子类和父类方法的逻辑可以不一致,但是传入参数、返回的返回值一致;
4.接口隔离原则(Interface Segregation Principle)
使用多个专门的接口,而不使用单一的总接口。
客户端即高层代码也就是低层代码的调用者,客户端不应该依赖哪些它不需要的接口。
from abc import ABC, abstractmethod # 动物接口-存在设计缺陷 # class Animal(ABC): # @abstractmethod # def walk(self): # pass # # @abstractmethod # def swim(self): # pass # # @abstractmethod # def fly(self): # pass # # ---------------高层代码 # # 具体动物类-青蛙 # # Class Tiger must implement all abstract methods # class Frog(Animal): # def swim(self): # print("青蛙水里游~") # # # # 具体动物类-老虎 # # Class Tiger must implement all abstract methods # class Tiger(Animal): # def walk(self): # print("老虎地上走") # 具体动物类-青蛙 # # Class Tiger must implement all abstract methods # class Swan(Animal): # def fly(self): # print("天鹅天上飞~") # 修复Animal单一接口设计缺陷 """ 使用多个专门接口 不使用单一接口 这样客户端不依赖哪些它不需要的接口 """ class LandAnimal(ABC): @abstractmethod def walk(self): pass class WaterAnimal(ABC): @abstractmethod def swim(self): pass class FlyAnimal(ABC): @abstractmethod def fly(self): pass # ---------------高层代码 # 具体动物类-老虎 class Tiger(LandAnimal): def walk(self): print("老虎地上走") # 具体动物类-青蛙 class Frog(LandAnimal, WaterAnimal): def walk(self): print("青蛙水里游~") def swim(self): print("青蛙地上走~") # 具体动物类-青蛙 class Swan(LandAnimal, WaterAnimal, FlyAnimal): def fly(self): print("天鹅天上飞~") def walk(self): print("天鹅天地上走~") def swim(self): print("天鹅天水中游~") if __name__ == '__main__': a1 = Tiger() a1.walk() a2 = Frog() a2.walk() a2.swim() a3 = Swan() a3.walk() a3.swim() a3.fly()
5.依赖倒置原则(Dependency Inversion Principle)
高层模块不应该依赖地层模块,二者都应该依赖其约定的接口。
接口的设计原则不应该依赖代码细节,代码细节应该依赖接口。即先定义接口,方法里面的逻辑根据接口约定实现。
即针对接口编程,而不是针对实现编程。
面向接口编程的好处就是低层代码一旦修改,调用低层代码的高层代码,不需要修改;
因为双方都遵循约定的接口,约定包括:调用底层代码的方法的名称、入参、返回值。
底层代码需要修改不能修改接口中定义的内容,而是修改方法里面的代码逻辑。
四、设计模式分类
设计模式本质是针对面向对象编程而提出的设计准则。
设计模式共计23个,分为3大类。
可创建型(Creational):创建型模式主要用于创建对象
结构型(Structural):结构型模式主要用于处理类或对象的组合进行协同工作
行为型(Behavioral):行为型模式主要用于描述类或对象的行为即方法,类或对象应怎样交互?怎样分配职责?
由于篇幅原因,我把23个设计模式拆分为23篇文章, 逐一讲解;
1.创建型模式
创建型模式:主要聚焦在在隐藏底层代码的前提下,如何创建1个对象?分为5个子类。
原型模式
2.结构型模式
结构型模式:主要聚焦在 多个类之间应该组织成1种什么结构?才能一起协同工作,分为7个子类。
装饰模式
享元模式
3.行为型模式
行为型模式:主要聚焦在类中的方法,如何通过方法完成各某种行为,分为11个子类。
命令模式
迭代器模式
中介者解释器模式
备忘录模式
状态模式
访问者模式