本篇文章是作者对23种设计模式学习的一个总结,包含设计模式的三大分类(创建型5种,结构型7种,行为型11种)和七个面向对象设计原则,为了方便大家学习,现将23种设计模式的链接进行了整理,希望对大家有所帮助。
23种设计模式源码地址:GitHub - lkydog/Design-Pattern: ⭐java实现,23种设计模式
一、什么是设计模式
设计模式一种在软件开发种非常重要的编程技巧,它提供了经过验证的解决方案,可以使代码更加可读、可扩展和可维护,我们可以将常见的变成模式抽象出来,从而形成一组通用的解决方案,应用于不同的情况。
ps:设计模式代表的是一种思想,至于怎么千变万化就看大家的了。
二、设计模式的三大分类及对应模式(导航)
注意:以下学习难度和使用频率的星级,仅代表个人观点。
2.1 创建型模式(5种)
定义:主要涉及对象创建的机制,按照合适的方式避免直接创建对象,在系统运行过程中降低对象创建和管理的负担。
1.单例模式-Singleton Pattern【学习难度:★☆☆☆☆,使用频率:★★★★☆】
- 定义:确保一个类最多只有一个实例,并提供一个全局访问点。
- 描述:包含饿汉式2种、懒汉式4种、静态内部类、枚举等实现方式。
2.工厂模式-Factory Pattern【学习难度:★★☆☆☆,使用频率:★★★★★】
- 定义:提供一个公共的接口,使得可以在不暴露对象创建逻辑的情况下创建。
- 描述:包含简单工厂模式、方法工厂模式以及抽象工厂模式。简单工厂和方法工厂以卖包子为例,抽象工厂以卖包子和卖蛋糕为例。
3.抽象工厂模式(工厂模式已包含,不再赘述)
4.建造者模式-Builder Pattern【学习难度:★★★☆☆,使用频率:★★☆☆☆】
- 定义:封装一个复杂对象构造过程,并允许按步骤构造。
- 描述:以肯德基套餐为例。
5.原型模式-Prototype Pattern【学习难度:★★★☆☆,使用频率:★★★☆☆】
- 定义:通过复制现有实例来创建新的实例,无需知道相应类的信息。
- 描述:以英雄联盟塞拉斯窃取其他英雄大招为例。
2.2 结构型模式(7种)
定义:主要关注对象组合的方式,解决对象之间的关系,解决子系统之间的耦合度和扩展问题。
1.适配器模式-Adapter Pattern【学习难度:★★☆☆☆,使用频率:★★★☆☆】
- 定义:允许不兼容的接口之间进行合作。
- 描述:以英汉互译为例,包含类适配器、对象适配器、接口适配器。
2.装饰者模式-Decorator Pattern【学习难度:★★★☆☆,使用频率:★★★☆☆】
- 定义:动态的将新功能附加到对象上。
- 描述:以LOL中盲僧学习技能(Q、W、E、R)为例。
3.代理模式-Proxy Pattern【学习难度:★★☆☆☆,使用频率:★★★★☆】
- 定义:给某一个对象提供一个代理对象,并由代理对象控制对原有对象的引用。
- 描述:以房屋中介为例,包含静态代理、JDK动态代理和Cglib代理。
4.外观模式-Facade Pattern【学习难度:★☆☆☆☆,使用频率:★★★★★】
- 定义:隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。
- 描述:以旅行社为例。
5.桥接模式-Bridge Pattern【学习难度:★★★☆☆,使用频率:★★☆☆☆】
- 定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
- 描述:以不同品牌手机和蓝牙耳机为例。
6.组合模式-Composite Pattern【学习难度:★★★☆☆,使用频率:★★★★☆】
- 定义:将对象组合成树形的层次结构,用来表示“整体-部分”的关系。
- 描述:以算数表达式为例。
7.享元模式-Flyweight Pattern【学习难度:★★★★☆,使用频率:★★☆☆☆】
- 定义:通过共享的方式减少创建对象的数量,以减少内存占用和提升性能。
- 描述:以共享单车为例。
2.3 行为型模式(11种)
定义:主要关注对象之间的交流和协作,解决类或对象之间的交互问题。
1.策略模式-Strategy Pattern【学习难度:★☆☆☆☆,使用频率:★★★★★】
- 定义:定义了一系列的算法,并将每个算法封装起来,是他们可以相互替换。
- 描述:以刷视频选择视频平台为例。
2.模板模式-Template Pattern【学习难度:★★☆☆☆,使用频率:★★★★☆】
- 定义:在抽象类中定义算法的骨架,把具体的操作留给子类来实现。
- 描述:以订外卖为例。
3.观察者模式-Observer Pattern【学习难度:★★★☆☆,使用频率:★★★★☆】
- 定义:它定义了对象之间的一对多依赖关系,当一个对象的状态发生变化时,它所有的依赖对象都会自动收到通知并更新自身。
- 描述:以报纸和报纸订阅者为例。
4.迭代器模式-Iterator Pattern【学习难度:★★★☆☆,使用频率:★★★★☆】
- 定义:提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。
- 描述:以遍历班级学生为例。
5.解释器模式-Interpreter Pattern【学习难度:★★★★★,使用频率:★☆☆☆☆】
- 定义:定义了一种语言,并定义该语言中语句的解释器,从而允许以编程方式定义语法、解析语法以及处理语法中的解释器。
- 描述:以四则运算为例。
6.中介者模式-Mediator Pattern【学习难度:★★★☆☆,使用频率:★★☆☆☆】
- 定义:用于降低多个对象之间的耦合度,通过引入一个中介者对象来协调对象之间的交互。
- 描述:以物流公司协调运输公司和商家为例。
7.责任链模式-Chain Pattern【学习难度:★★★☆☆,使用频率:★★☆☆☆】
- 定义:使用一条链来处理请求,该请求沿着链顺序传递,直到有对象处理该请求为止,从而达到解耦请求发送者和请求处理者的目的。
- 描述:以学校请假审批流程为例。
8.命令模式-Command Pattern【学习难度:★★★☆☆,使用频率:★★★★☆】
- 定义:将请求封装成一个对象,从而使不同的请求可以参数化、队列化、记录日志、撤销和重做等操作。
- 描述:以餐厅点餐为例。
9.备忘录模式-Memento Pattern【学习难度:★★★☆☆,使用频率:★★★☆☆】
- 定义:允许将对象的内部状态保存到外部,从而在需要时可以将对象恢复到之前的状态。
- 描述:以为本编辑器为例。
10.状态模式-State Pattern【学习难度:★★★☆☆,使用频率:★★☆☆☆】
- 定义:允许对象在内部状态发生改变时改变它的行为。
- 描述:以自动售卖机状态为例。
11.访问者模式-Visitor Pattern【学习难度:★★★★☆,使用频率:★☆☆☆☆】
- 定义:用于在不修改已有对象结构的情况下,定义新的操作方式。
- 描述:以“旅游参观”为例。
三、七大原则
设计模式的七大原则,也称为"SOLID原则",是面向对象设计种的基本准则。
3.1 单一职责原则(Single Responsibility Principle,SRP)
- 概念:一个类应该只有一个职责,即一个类应该只负责一个功能领域中的相应职责。
- 例子:比如一个“水果”类,如果既包括了“水果基本属性”又包括了“水果存储方式”,那么这个类就存在着两个职责,违反了单一职责原则。正确的做法是将“水果基本属性”和“水果存储方式”拆分为两个类。
3.2 开放封闭原则(Open-Closed Principle,OCP)
- 概念:对扩展开放,对修改关闭。
- 例子:比如一个计算器程序,如果每次添加新的计算方法都要修改原有代码,那么这个程序就违反了开放封闭原则。正确的做法是为每一种计算方法单独编写一个类或方法,这样当需要添加新的计算方法时,只需要增加一个新的类或方法即可,而不需要修改原有代码。
3.3 里氏替换原则(Liskov Substitution Principle,LSP)
- 概念:所有引用基类对象的地方,都能透明地使用其子类对象,而不会影响程序的正确性。
- 例子:比如一个“动物”类和它的子类“鸟”类,如果鸟类无法继承动物类的方法或需要对动物类的方法进行重写才能满足其独有特性,那么这个子类就违反了里氏替换原则。
3.4 接口隔离原则(Interface Segregation Principle, ISP)
- 概念:客户端不应该依赖于他们不需要的接口。即一个类对一个类的依赖应该建立在最小的接口上。
- 例子:比如一个汽车类,如果其中包含了所有汽车可能用到的接口(加速、刹车、转向等等),其实有些汽车可能用不到这些接口,那么这个类就违反了接口隔离原则。正确的做法是将不同的接口分别放到不同的类中。
3.5 依赖倒置原则(Dependency Inversion Principle,DIP)
- 概念:高层模块不应该依赖低层模块,而是应该依赖它们的抽象。即模块间应依赖于接口或抽象类,而不是实现类。
- 例子:比如一个销售管理系统中,低层模块“数据库操作”模块依赖于高层模块“订单管理”模块。这样的设计不仅会增加耦合度,还会导致数据泄漏。正确的做法是将抽象的“数据库操作”模块放到更高的抽象层中,由“订单管理”模块调用。
3.6 迪米特法原则(Law of Demeter,LoD)
- 概念:减少对象之间的依赖,即一个对象应当对其它对象有尽可能少的了解,不和陌生人说话。
- 例子:比如一个电商网站,如果一个类要发送邮件通知顾客下单成功,带有的信息应该只包括商品信息和顾客账户信息,而不应该包括商品仓库信息、物流信息等等,这样的设计能够减少依赖关系,避免类之间的耦合。
3.7 组合/聚合复用原则(Composition/Aggregation Reuse Principle,CARP)
- 概念:应该优先使用组合或聚合关系复用,而不是使用继承关系复用。
- 例子:比如一个“汽车轮子”类和它的子类“越野车轮子”类,如果采用继承关系来实现越野车轮子,那么可能会导致“越野车轮子”过于臃肿,而且未必完全符合实际需求。正确的做法是将两个类一同纳入到“汽车”类中,使用组合或聚合关系复用(即“汽车”类拥有“汽车轮子”类和“越野车轮子”类的实例)。
四、总结
正确地使用设计模式可以提高代码的可维护性和可扩展性,但错误地使用可能会增加代码复杂度、学习成本和性能开销。还是那句话,设计模式只是一个工具,不要为了使用设计模式而用。