什么是设计模式
Christopher Alexander说过:“每一个设计模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复的劳动”.尽管Alexander所指的是城市和建筑模式,但他的思想也同样与用于面向对象设计模式,只是在面向对象的解决方案里,我们用对象和接口代替了墙壁和门窗。两类模式的核 心都在于提供了相关问题的解决方案。--- 《设计模式:可复用面向对象软件的基础》
一般而言,一个模式有四个基本要素:
1,模式名称(pattern name)
用一两个词来描述问题的问题,解决方案和效果。
2,问题 (problem)
描述了应该在何时使用模式。
3,解决方案 (solution)
描述了设计的组成成分,他们之间的相互关系以及各自的职责。
4,效果 (consequences)
描述了模式应用的效果及使用模式应权衡的问题
设计模式怎样解决设计问题
代码复用的关键就是对新需求和已有需求发生变化的预见性,要求你的设计能够响应的改进
设计模式可以确保系统能够以特定方式变化, 避免重新设计, 同时保证系统的健壮性, 每个模块可以独立演进, 独立于其他方面
设计模式主要解决的八类问题
通过显示地指定一个类来创建对象
问题: 在创建对象时指定类名使你受特定实现的约束(只能使用某个具体的类),当未来我们要创建一个新的类对象的时候, 就需要修改我们所有使用指定类
方案: 间接的创建对象
模式: 使用抽象工厂、工厂方法等设计模式
对特殊操作的依赖
问题: 为请求指定一个特殊操作时, 完成改请求的方式就固定下来, 写死了代码
方案: 在编译时或者运行时根据请求动态改变响应请求的方法
模式:责任链、命令模式
对硬件和软件平台的依赖
问题:外部的操作系统接口和应用编程接口在不通的软硬件平台上时不同的,依赖于特定平台的软件很难移植到其他平台
方案:设计系统时限制其平台相关性
模式:抽象工厂、桥接
对对象表示或者实现的依赖
问题:知道对象怎样表示、保存、定位或者实现的客户在对象发生变化时也需要变化
方案:对客户隐藏这些信息组织连锁变化设计
模式:抽象工厂、桥接模式、备忘录模式、代理模式
算法依赖
问题:算法在开发和复用时常常被扩展、优化和替代。依赖某个特定算法的对象发生变化时不得不变化
方案:将可能发生变化的算法孤立起来设计
模式:建造者、迭代器、策略、模版方法、访问者
紧耦合
问题:紧耦合的类和很难独立的被复用,彼此相互依赖,要改变或者删掉一个类,必须理解其他类,很难移植和维护
方案:使用抽象耦合和分层技术提高系统的松散耦合性设计
模式: 抽象工厂、命令、门面、中介者、观察者、责任链
通过生成子类来扩充功能
问题:定义子类需要对父类有深入了解,子类还会导致类保证,因为简单的扩充也需要引入许多新的子类
方案:通过组合技术和具体的委托技术这种灵活的方式,可以定一个字累,且将它的实例和已存在的实例进行组合引入定制的功能设计
模式:桥接、责任链、组合、装饰器、观察者、策略
不能方便的对类进行修改
问题:不得不休一个难以修改的类,对类的任何改变会要求修改许多依旧存在的其他子类
方案:直接对类进行功能增强,而不是修改类设计
模式:适配器、装饰器等
设计模式的分类
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式的六大原则
总原则:开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。
1、单一职责原则
不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。
2、里氏替换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科历史替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
5、迪米特法则(最少知道原则)(Demeter Principle)
就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。
最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。
6、合成复用原则(Composite Reuse Principle)
原则是尽量首先使用合成/聚合的方式,而不是使用继承。
参考资料:《设计模式:可复用面向对象软件的基础》
《设计模式解决的8个问题场景你了解么》
《二十三种设计模式全解析》