设计模式概述
设计模式(Design Pattern)代表了最佳实践,通常是软件开发人员在开发中面临的一般问题的解决方案,这些解决方案是众多软件开发人员经过相当长一段时间的试错后总结出来的。任何被广泛使用的技术或者功能都会有特定的经验总结,因此面向对象有面向对象的设计模式,软件架构有软件架构的设计模式,数据口有数据库的设计模式。对于转发类型的芯片,其软件架构有一定的设计模式,同时可编程的微码也存在一定的设计模式与设计原则。当然,我们常说的设计模式默认情况下指的是面向对象设计模式。
对于那些具有丰富的开发经验的开发人员,学习设计模式有助于了解在软件开发过程中所面临的问题的最佳解决方案;对于那些经验不足的开发人员,学习设计模式有助于通过一种简单快捷的方式来学习软件设计。
目前设计模式在Design Patterns中共包含23种。这些设计模式可以分三大类:
- 创建型模式(Creational Patterns)
- 结构型模式(Structural Patterns)
- 行为型模式(Behavioral Patterns)
创建型模式(Creational Patterns)
- 工厂模式(Factory Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
- 单例模式(SingletonPattern)
- 建造者模式(Builder Pattern)
- 原型模式(Prototype Pattern)
结构型模式(Structural Patterns)
- 适配器模式(Adapter Pattern)
- 桥接模式(Bridge Pattern)
- 组合模式(Composite Pattern)
- 装饰器模式(Decorator Pattern)
- 外观模式(Facade Pattern)
- 享元模式(Flyweight Pattern)
- 代理模式(Proxy Pattern)
行为型模式(Behavioral Patterns)
- 责任链模式(Chain of Responsibility Pattern)
- 命令模式(Command Pattern)
- 解释器模式(Interpreter Pattern)
- 迭代器模式(Iterator Pattern)
- 中介者模式(Mediator Pattern)
- 备忘录模式(Memento Pattern)
- 观察者模式(Observer Pattern)
- 状态模式(State Pattern)
- 策略模式(Strategy Pattern)
- 模板模式(Template Pattern)
- 访问者模式(Visitor Pattern)
设计原则
接口标准化是一个产业强盛的标志,有很强大的一个团队在维护标准接口。接口把各个模块隔离开来,进而实现了高效的协作。设计模式是实际开发过程中经验总结,从这个角度来讲设计原则这些精华要比实际掌握哪个设计原则要重要。
- 依赖倒置原则(DIP):高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定);抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖抽象(稳定)。抽象提出是核心。具体内容:针对接口编程,依赖于抽象而不依赖于具体。
- 开放封闭原则(open close principle,OCP):对扩展开放,对更改封闭。类模块应该是可扩展的,但是不可修改。面对需求的变化不是漫天修改,二是增加一部分内容来实现。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
- 单一职责原则(SRP):一个类应该仅有一个引起它变化的原因;变化的方向隐含类的责任。一个类接口与行数是有限制的,避免太多功能把类拉扯到不同的方向。
- Liskov替换原则(Liskov Substitution Principle,LSP):子类必须能够替换他们的基类(IS-A);继承表达类型抽象。所有需要父类的地方子类都是应该可以传过去使用。一个反例是很多时候写代码子类中发现父类几个方法不能使用,直接使用异常方式抛出,这就使用父类的地方,子类没有办法使用了,违背了替换原则。实际两个类关系更可能是一个并列关系。里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
- 接口隔离原则(Interface Segregation Principle,ISP):不应该强迫客户程序依赖他们不适用的方法;接口应该小而完备。接口要合理定义,同时接口内部实现函数的权限是明确区分下来的,是public、private都要明确定义。这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
- 合成复用原则(Composite Reuse Principle):优先使用对象组合,而不是类继承:累积成通常为“白箱复用”,对象组合通常为“黑箱复用”;继承在某种程度上破坏了分装性,子类父类的耦合度高;而对象组合只要求被组合的对象具有良好的定义的接口,耦合度低。不要掉到固有的继承思维当中,合理使用面向对象的继承。尽量使用合成/聚合的方式,而不是使用继承。
- 分装变化点:使用分装来创建对象之间的分界层,让设计者可以在分界层一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
- 针对接口编程,而不是针对实现编程:不讲变量类型的声明为某个特定的具体类,二是声明为某个接口;客户程序无需获知对象的具体类型,只需要知道对象所具有的接口;减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案。和第一个依赖倒置原则是同一件事情不同角度。
- 迪米特法则:又称最少知道原则(Demeter Principle):一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
设计模式回顾
从迭代器开始,我们将类中数据结构的遍历和类的功能实现分离出来,本质上使用了工厂模式;
其次我们学习了适配器模式,它将不同的接口进行适配,从而便于版本的兼容性以及其他功能;
然后我们学习了模板方法,使用模板面向抽象编程,便于新的子类的实现和管理;
之后学习了工厂模式,其实借用了模板模式来创建产品,是一种非常重要用处很广的一种方法;
然后我们学习了单例模式,有懒汉式、饿汉式等,生成关于某个类全局唯一的对象,注意多线程的影响;
之后是原型模式,用来复制复杂的对象,使用了clone方法,然后是builder模式,用一个新的类对已有的抽象接口进行整合和编程,从而构建出我们想要的东西;
然后是抽象工厂模式,使用了工厂模式,组合模式等模式,面向抽象编程,将抽象零件组装成抽象产品,便于具体工厂的创建,提高了代码的组件化和复用性;
然后是桥接模式,将类的功能层次和实现层次分割开来,便于对应的扩展和使用;
然后是策略模式,可以整体的替换策略,使用也很广泛;然后是组合模式,保证了同根同源,通过委托添加自己构成递归,树形结构,将具有树形特点的对象组合起来;
然后是装饰器模式,和组合模式的结构类似,同样是递归结构,从而可以不断的装饰,增加新的功能,很好用;
接着是visitor访问者模式,通过在类外访问类中的数据结构从而得到想要的结果,便于程序的可扩展性和组件化;
接着是责任链模式,推卸责任,根据问题的大小来考虑自己释放处理,本质是链表,便于职责分明;
然后是外观模式,通过整合各个类之间的调用关系,组建成了统一的接口(API),便于外部类的调用;
接着是仲裁者模式,将很多类之间互相关联的关系交给仲裁者处理,省去了各个类之间的嵌套和调动,有利于高内聚和低耦合,思路清晰,便于扩展;
然后是观察者模式,通过互相委托从而能够在被观察的类发生改变的时候得到相应的改变的信息并且处理;
然后是备忘录模式,通过在某一时刻的状态保存下来,便于恢复,在游戏中使用的比较多;
然后是状态模式,将状态当做类,从而职责分明,解除了很多繁琐的if和else这些分支逻辑,便于扩展;
然后是享元模式,轻量级对象,通过共用不变对象来实现;
然后是代理模式,懒加载真正的服务器,加快访问速度,代理是帮助服务器代理的;
然后是命令模式,将命令当做类,通过保存一些列命令,从而能够随时执行这些命令,需要清除命令的本质就是一些操作和数据;
最后是解释器模式,利用编程原理的方法,来更高层次的封装代码,将自己开发的java代码当做编译系统,从而不用改变java代码只修改更高语言层次的代码就能实现不同的功能。
参考:
https://blog.youkuaiyun.com/guorui_java/article/details/104026988
https://blog.youkuaiyun.com/a745233700/article/details/120371090