设计模式的思想 来自日常生活
- 设计模式的好处
- 六大原则
- 类别
- 创建型(创建对象)
- 结构型(构建模块之间的关系)
- 行为型(交互)
- 重要模式详述
- 单例模式
- 工厂模式
- 抽象工厂模式
- 建造者模式
- 装饰器模式
- 适配器模式
- 代理模式
- 迭代器模式
- 责任链模式
- 观察者模式
- 策略模式
浅浅了解一下,工作后,“以应用为目的”,再深入探究~
设计模式的好处
- 重用代码
- 让代码更容易被他人理解
- 保证代码可靠性
六大原则
SOLID(稳定的):首字母排序,34重复只取一个
-
单一职责原则(Single Responsibility Principle)
一个接口或者类只能有一个职责,它就负责一件事情
-
开闭原则(Open Close Principle)
对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码。想要达到这样的效果,需要使用接口和抽象类。
- 里氏代换原则(Liskov Substitution Principle)
任何基类可以出现的地方,子类一定可以出现。只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用。
-
迪米特法则,又称最少知道原则(Law of Demeter)
一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
-
接口隔离原则(Interface Segregation Principle)
使用多个隔离的接口,比使用单个接口要好,从而降低类之间的耦合度。
-
依赖倒转原则(Dependence Inversion Principle)
针对接口编程,依赖于抽象而不依赖于具体。
类别
创建型(创建对象)
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
- 单例模式
- 工厂模式
- 抽象工厂模式
- 建造者模式
- 原型模式
结构型(构建模块之间的关系)
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
- 适配器模式
- 装饰器模式
- 代理模式
- 外观模式
- 桥接模式
- 组合模式
- 享元模式
行为型(交互)
这些设计模式特别关注对象之间的通信。
- 策略模式
- 模板方法模式
- 观察者模式
- 迭代器模式
- 责任链模式
- 命令模式
- 备忘录模式
- 状态模式
- 访问者模式
- 中介者模式
- 解释器模式
重要模式详述
工作中,掌握它们就够了
单例模式
-
概述:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。主要解决一个全局使用的类频繁地创建与销毁,节约系统资源。
-
优点:
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。如:学校官网只有一个页面,只需一个对象
- 避免对资源的多重占用,如:写文件操作
-
缺点:
- 没有接口,不能继承
- 与单一职责原则冲突,因为这个类要实现管理自己的生命周期,包括初始化和回收等。
-
跑代码的一些想法:
- 先自己创建对象,提供一个获取该唯一对象的方法
- 用private修饰构造函数,这样就不能被实例化
- 懒汉和饿汉,懒汉-只有别人向它要对象才实例化,饿汉-类初始化时就实例化
工厂模式
- 概述:我们在创建对象时不会对客户端暴露创建逻辑,定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。主要解决接口选择的问题。
- 优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了
- 扩展性高,如果想增加一个产品(已有抽象产品),只要增加具体产品,修改工厂类就可以
- 屏蔽产品的具体实现,调用者只关心产品的接口
- 缺点:
- 每次增加一个产品时(没有抽象产品),都需要增加一个接口,具体产品类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖
为什么说工厂模式违反了开闭原则?
从头来说,我们定义了书籍作为接口,Java和数据库的书籍实现接口。然后来一个创建书籍的工厂类,到这,就是简单工厂模式了。如果有新的类型的书,比如C++,类是不用改,添加就行,但工厂类可是要修改的,这样就违反了开闭原则。
基于此,简单工厂模式适用场景较少。大多数情况下,我们会定义一个工厂接口,分别定义创建Java和数据库书籍的工厂类实现该接口,这样就算添加C++的书,只需要加一个工厂类即可,不用修改了!
这两种,前者是简单工厂模式,后者是工厂模式,再加上抽象工厂模式,应该有三种!
UML类图
抽象工厂模式
如果书籍,要生产多个子产品(文稿和视频),就需要抽象工厂。
Factory
是抽象类,不再是接口了
建造者模式
-
概述:使用多个简单的对象一步一步构建成一个复杂的对象。分而治之,便于维护。
-
优点:
- 建造者独立,易扩展
- 便于控制细节风险
-
缺点:
- 产品必须有共同点,范围有限制
- 如内部变化复杂,会有很多的建造类
-
跑代码的一些想法:
- 每个实体都定义成一个类,类的数量是指数级增长,太多了
建造者模式和工厂模式的区别
建造者模式偏重于组件的创建过程,所以会通过总控类来组装对象;而工厂模式偏重于“创建产品”的这个结果,一般不会有总控类。这段话不理解。
UML类图
MealBuilder
应该就是上述的总控类。
装饰器模式
- 概述:允许向一个现有的对象添加新的功能,同时又不改变其结构。用来动态地把不固定数量的零件组合成业务整体。
- 优点:
- 装饰类和被装饰类可以独立发展,不会相互耦合,可以动态扩展一个实现类的功能
- 缺点:
- 多层装饰比较复杂
- 应用场景:
- 银行的理财产品,保险等等
适配器模式
-
概述:将一个类的接口转换成客户希望的另一个接口,使得原本因为版本不兼容而不能一起工作的类可以一起工作。
-
优点:
- 可以让任何两个没有关联的类一起运行
- 提高了类的复用
- 增加了类的透明度
- 灵活性好
-
缺点:
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构
- 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类
-
应用场景
- 电压转换220V ~ 110V
- 空调制冷 ~ 制热
代理模式
-
概述:为其他对象提供一种代理以控制对这个对象的访问。
-
优点:
- 职责清晰
- 高扩展性
- 智能化
-
缺点:
- 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢
- 实现代理模式需要额外的工作,有些代理模式的实现非常复杂
迭代器模式
-
概述:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
-
优点:
- 它支持以不同的方式遍历一个聚合对象
- 迭代器简化了聚合类
- 在同一个聚合上可以有多个遍历
- 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码
-
缺点:
- 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
责任链模式
-
概述:在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
-
优点:
- 降低耦合度。它将请求的发送者和接收者解耦
- 简化了对象。使得对象不需要知道链的结构
- 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任
- 增加新的请求处理类很方便
-
缺点:
- 不能保证请求一定被接收
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用
- 可能不容易观察运行时的特征,有碍于除错
-
应用场景
- Spring 拦截器
观察者模式
-
概述:当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知依赖它的对象。
-
优点:
- 观察者和被观察者是抽象耦合的
- 建立一套触发机制
-
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
-
应用场景
- 大牛(被观察者)发布博客,所有粉丝(观察者)收到通知
- 股票同时交易的时候,股价会相应变动,影响后来者的交易价格
策略模式
-
概述:一个类的行为或其算法可以在运行时更改。
-
优点:
- 算法可以自由切换
- 避免使用多重条件判断
- 扩展性良好
-
缺点:
- 策略类会增多
- 所有策略类都需要对外暴露