设计模式
什么是设计模式
软件设计模式是可解决一类软件问题并能重复使用的软件设计方案。模式的核心思想是通过增加抽象层,把变化部分从那些不变部分里分离出来。
如何学习设计模式
在学习设计模式时,要思考一下几点:
1> 动机:该模式用来解决什么样的特定设计问题?可以用来改进哪些不良设计?
2> 解决方案:该模式解决不良设计的具体方案?描述设计的组成成分、相互关系及各自的职责和协作方式。
3> 效果:使用模式的效果和所需做出的权衡取舍?
4> 适用环境:该模式在什么情况下使用?
5> 应用:该模式有哪些实际应用?
常用的设计模式
图说设计模式这个写的很清晰,另外再结合设计模式之工厂、UML8设计模式(GRASP模式、GOF模式)、设计模式PPT-工大这三个PPT进行学习。
1. 创建型模式
创建型模式是类在实例化时使用的模式。当一些系统在创立对象时,需要动态地决定怎样创建对象,创建哪些对象。创建型模式告诉我们怎样构造和包装这些动态的决定。
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
- 建造者模式(Builder)
- 原型模式(Prototype)
- 单例模式(Singleton)
2. 结构型模式
结构型模式描述类和对象怎样结合在一起成为较大的结构。结构型模式描述两种不同的东西:类与类的实例。
- 适配器模式(Adapter)
- 桥接模式(Bridge)
- 组合模式(Composite)
- 装饰者模式(Decorator)
- 外观模式(Facade)
- 享元模式(Flyweight)
- 代理模式(Proxy)
3. 行为型模式
行为型模式涉及到算法和对象职责间的分配。行为型模式不仅是关于类和对象的,而且还描述它们之间的作用。这些模式刻画了运行时刻难以跟踪的复杂的控制流,它帮助软件设计者在设计软件的时候把注意力从控制流转移到对象间的联系上。
- 职责链模式(Chain of Responsibility)
- 命令模式(Command)
- 解释器模式(Interpreter)
- 迭代器模式(Iterator)
- 中介者模式(Mediator)
- 备忘录模式(Memento)
- 观察者模式(Observer)
- 状态模式(State)
- 策略模式(Strategy)
- 模板方法模式(Template Method)
- 访问者模式(Visitor)
设计模式的原则
设计模式就是实现了以下原则,从而达到代码复用、增加可维护性的目的。
"开-闭"原则(Open Closed Principle)
定义:软件对扩展是开放的,对修改是关闭的。开发一个软件时,应可以对其进行功能扩展(开放),在进行扩展的时候,不需要对原来的程序进行修改(关闭)。
好处:可以在软件完成后对软件进行扩展,加入新的功能,这样,软件就可通过不断的增加新模块满足不断变化的新需求,在软件可用性上非常灵活;由于不修改软件原来的模块,不用担心软件的稳定性。
单一职责原则(Single Responsibility Principle)
就一个类而言,应该仅有一个引起它变化的原因。每一个引起类变化的原因就是一个职责,当类具有多职责时,应把多余职责分离出去,分别创建一些类来完成每一个职责。每一个职责都是一个变化的轴线,当需求变化时会反映为类的职责的变化。
interface Modem { public void dial(String pno); public void hangup(); public send(char c); public char recv(); }
Modem类有两个职责:连接管理和数据通信,应将它们分离。
里氏代换原则(Liskov Substitution Principle)
定义:“继承必须确保超类所拥有的性质在子类中仍然成立”,当一个子类的实例能够替换任何其超类的实例时,它们之间才具有is-A关系。
里氏替换原则是继承复用的基石,只有当派生类可以替换掉其基类,而软件功能不受影响时,基类才能真正被复用,派生类也才能够在基类的基础上增加新的行为。
LSP本质:在同一个继承体系中的对象应该有共同的行为特征。
例子:企鹅是鸟吗? 生物学:企鹅属于鸟类 LSP原则:企鹅不属于鸟类,因为企鹅不会“飞”
违反LSP的后果:有可能需要修改客户代码
依赖倒置原则(Dependence Inversion Principle)
所谓依赖倒置原则就是要依赖于抽象,不要依赖于具体。简单的说就是要针对接口编程,不要针对实现编程,这样就降低了客户与实现模块间的耦合。
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变化时,上层也要跟着变化,这就会导致模块的复用性降低而且大大提高了开发的成本。
面向对象的开发很好的解决了这个问题,一般的情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变化,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序域实现细节的耦合度。
PS:为什么要使用“倒置”一词,依赖倒置的意义是什么?简单地说,传统的过程性系统的设计办法倾向于使高层次的模块依赖于低层次的模块;抽象层次依赖于具体层次。倒置原则是要把这个错误的依赖关系倒转过来,这就是依赖倒置原则的来由。
接口隔离原则(Interface Segregation Principle)
定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
我们可以把这两个定义概括为一句话:建立单一接口,不要建立臃肿庞大的接口。再通俗一点讲:接口尽量细化,同时接口中的方法尽量少。
设计模式六大原则(4):接口隔离原则这个讲的很形象。
迪米特法则(Law of Demeter)
又叫作最少知道原则(Least Knowledge Principle, LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。