设计模式应用有感总结
1、桥接设计模式
(1)从形式上看,就是将一个抽象(接口)作为成员变量放入另一个抽象类中,以实现【抽象与实现的解耦】,这样ImplementorImpl与AbstractImpl可以各自做自己的事情而互不影响,可以独立变化,而又自由组合。有点类似对象的链接。接口实现对象一般都是通过抽象类继承类构造函数参数传进去,构造函数参数决定桥接的是哪个实现接口的对象,然后由实现接口的对象执行任务。
2、代理设计模式
(1)代理类可以对委托类进行功能扩展,所以当需要对某个类功能(操作或方法)进行扩展时可以使用代理模式
3、享元模式
基本介绍
(1)享元模式,又称蝇量模式:
(2)运用共享技术实现大量细粒度对象的复用
应用
(1)享元模式是池技术的重要实现方式
(2)池技术:String 常量池、数据库连接池、缓冲池
(3)常用于系统底层开发,解决系统的性能问题:如数据库连接池,池中是创建好的连接对象,若池中有符合需求的对象时直接用,避免重新创建;若池中没有符合需求的,则创建一个
要求
(1)细粒度、共享对象
(2)将对象的信息分为两个部分
(1)内部状态:指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变的状态
(2)外部状态:指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态
角色
(1)FlyWeight:抽象的享元角色,产品的抽象类,定义了对象的外部状态和内部状态的接口或实现
(2)ConcreteFlyWeight:具体的享元角色,产品的实现类,实现了抽象角色定义的相关业务
(3)UnSharedConcreteFlyWeight:不可共享的角色,一般不会出现在享元工厂中
(4)FlyWeightFactory:享元工厂类,内部提供一个池容器,储存ConcreteFlyWeight,同时提供从池中存取数据的操作
事项
(1)享:共享,元:对象
(2)应用场景:系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化时
(3)一般用 HashMap / HashTable 存储 ConcreteFlyWeight,key作为唯一标识码判断 ConcreteFlyWeight
(4)优点
(1)解决重复对象的内存浪费的问题,减少了对象的创建,降低了程序内存的占用,提高效率
(2)提高了系统的复杂度,需要分离出内部状态和外部状态
(5)缺点
(1)提高了系统的复杂度,需要分离出内部状态和外部状态。而外部状态具有固化特性,不应该随着内部状态的改变而改变
(2)享元模式需要额外维护对象缓存池。
(6)例子
春运买火车票是一件疯狂的事情,同一时刻会有大量的查票请求涌向服务器,服务器必须做出应答来满足我们的购票需求。试想,这些请求包含着大量的重复,比如从A地到B地的车票情况,如果每次都重复创建一个车票查询结果的对象,那么GC任务将非常繁重,影响性能,这就用到了我们的享元模式。当然也会有不重复的请求,比如我想购买从A地到B地的高铁票,而你想买从A地到B地的动车票。
4、命令模式
定义:命令是对命令的封装,每一个命令都是一个操作,请求方发出请求,接收方接收请求,并执行操作。命令模式解耦了请求方和接收方,命令模式属于行为型模式
命令模式中的4个角色:
(1)接收者角色(Receiver):负责具体执行一个请求
(2)命令角色(ICommand):定义需要执行的所有命令行为
(3)具体的命令角色(ConcreteCommand):内部维护一个Receiver
(4)请求者角色(Invoker):接收客户端的命令,并执行命令
例子 :遥控操作电视
5、责任链模式
责任链模式的优点如下:
(1)降低了对象之间的耦合度
发送者无需知道最终由哪一个handler处理其请求,也无需知道请求的传递过程
handler无需知道是哪一个发送者发送的请求,就像奖学金评选系统一样,本科生、研究生和博士生都可能是申请者
(3)增强了系统的可扩展性
如果新增handler无需修改请求者的代码逻辑,满足开闭原则
(4)增强了给对象指派职责的灵活性
随着工作流程的变化,可以动态地改变链内的handler、可以动态地调整handler的次序,还可以动态地增加或删除handler
(5)简化了对象之间的连接
每个对象只需保持一个指向其后继者的next引用,不需保持其他所有处理者的引用,避免了使用众多的 if···else 语句。
(6)责任分担
每个handler只需要处理自己分内的工作,分外的工作可以传递给下一个handler去完成
这样的话,每个handler的分工明确,符合类的单一职责原则
自己对增强了给对象指派职责的灵活性的理解
以请假审批为例,使用list记录责任链
可以通过set操作,将组长换成方向负责人
可以通过swap操作,调整部长和总监的审批顺序(不太恰当的例子)
可以通过add(index, element)操作,在指定位置增加handler
可以通过remove操作删除handler
责任链模式具有如下缺点:
(1)不能保证每个请求一定被处理:传入责任链的请求,可能直到链的末尾都没有对应的handler可以处理它
(2)对比较长的责任链,请求的处理可能涉及多个handler,系统性能将受到一定影响。
(3)责任链建立的合理性由客户端保证,增加了客户端的复杂性
(4)可能会由于责任链的错误设置而导致系统出错,如循环调用
(5)自己的疑惑: 为什么要由客户端创建责任链,权利下放很可能会出大问题的?
6、适配器模式
- 源(Adapee)角色:现在需要适配的接口。(比如:猫)
- 目标(Target)角色:这就是所期待得到的接口(类适配器模式,目标不可以是类)(一般是接口)
- 适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。
7、观察者模式
观察者模式,也被称为发布订阅模式,是一种行为型设计模式,也是在实际的开发中用得比较多的一种模式,当对象间存在一对多关系时,就可以使用观察者模式。定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象(观察者对象)都得到通知并被自动更新。
如何实现的?
观察者模式首先有一个被观察类,这个类中有一个 ArrayList 存放观察者们。除此以外还应有类状态和设置和获取状态的方法,状态改变时通知所有观察者,观察者类可以有个抽象类,所有的观察者类继承这个抽象类,观察者类有它要观察的对象。
举例实现
观察者模式使用两个类 Subject、Observer 。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。
ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式。
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
关键代码:在抽象类里有一个 ArrayList 存放观察者们。
应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
8、修饰模式
定义修饰模式:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
修饰模式主要创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
9、门面模式
门面模式
门面模式(Facade Pattern)又叫外观模式,提供了一个统一的接口,提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构性模式。
其实,在我们日常的编码过程中,我们都在有意无意地大量使用门面模式,但凡只要高层模块需要调度多个子系统(2个以上类对象),我们都会自觉地创建一个新类封装这些子系统,提供精密接口,让高层模块可以更加容易简介调用这些子系统的功能。尤其是现阶段各种第三方SDK,各种块原类库,很大概率都会使用门面模式。尤其是你觉得调用越方便的,门面模式适用的一般更多。
门面模式的应用场景
1、子系统越来越复杂,增加门面模式提供接口
2、构建多层系统结构,利用门面对象作为每层的入口,简化层间调用
门面模式的通用写法
门面模式主要包含2种角色:
外观角色(Facade):也称门面角色,系统对外的统一接口;
子系统角色(SubSystem):可以同时有一个或多个SubSystem。每个SubSytem都不是一个单独的类,而是一个类的集合。SubSystem并不知道Facade的存在,对于SubSystem而言,Facade只是另一个客户端而已(即Facade对SubSystem透明)。
下面是门面模式的通用代码,首先分别创建3个子系统的业务逻辑SubSystemA、SubSystemB、SubSystemC,代码很简单:
门面模式业务场景实例
比如信誉卡积分兑换礼品的商城,这礼品商城中的大部分功能并不是全部重新开发的,而是要去对接已有的各个子系统,这些子系统可能涉及到积分系统、支付系统、物流系统的接口调用/如果所有的接口调用全部由前端发送网络请求去调用现有的接口的话,一则会增加前端开发人员的难度,二则会增加一些网络请求影响页面的性能。这个时候就可以发挥门面模式的优势了。将所有现成的接口全部整合到一个类中,由后端提供统一的接口给前端调用,这样前端开发人员就不需要关心各接口的业务关系,只需要把精力集中在页面交互上。下面我们用代码模拟下这个场景。
门面模式的优缺点
优点:
1、简化了调用过程,无需深入了解子系统,以防给子系统带来风险。
2、减少系统依赖、松散耦合
3、更好地划分访问层次,提高了安全性
4、遵循迪米特法则,即最少知道原则
缺点:
1、当增加子系统和扩展系统行为时,可能容易带来未知风险
2、不符合开闭原则
3、某些情况下可能违背单一职责原则
10、组合模式
组合模式中的角色:
Component抽象组件:为组合中所有对象提供一个接口,不管是叶子对象还是组合对象。
Composite组合节点对象:实现了Component的所有操作,并且持有子节点对象。
Leaf叶节点对象:叶节点对象没有任何子节点,实现了Component中的某些操作。
组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别的对象。
使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句活说,在大多数情况下,我们可以忽略对象组合和个别对象之问的差别。
11、备忘录模式
备忘录模式又称快照模式,或者令牌模式。是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态,属于行为型模式。
发起人角色(Originator):负责创建一个备忘录,记录自身需要保存的状态,具备状态回滚功能
备忘录角色(Memento):用于存储Originator的内部状态,可以防止Originator以外的对象访问
备忘录管理员角色(Caretaker):负责存储。提供管理员备忘录,无法对备忘录内容进行操作和访问
12、中介模式
1. 核心思想
由中介来承接房客与房东之间的交互过程,可以使得整个租房过程更加畅通、高效。这在程序中叫作中介模式,中介模式又称为调停模式。
在很多系统中,多个类很容易相互耦合,形成网状结构。中介模式的作用就是将这种网状结构分离成星型结构。经过这样的调整后,对象之间的结构更加简洁,交互更加顺畅。
2. 设计要点
中介模式主要有以下三个角色,在设计中介模式时要找到并区分这些角色:
交互对象(InteractiveObject):要进行交互的一系列对象。
中介者(Mediator):负责协调各个对象之间的交互。
具体中介者(Mediator):中介的具体实现。
3. 优缺点
优点
Mediator将原本分布于多个对象间的行为集中在一起,作为一个独立的概念并将其封装在一个对象中,简化了对象之间的交互。
将多个调用者与多个实现者之间多对多的交互关系,转换为一对多的交互关系,一对多的交互关系更易于理解、维护和扩展,大大减少了多个对象之间相互交叉引用的情况。
缺点
中介者承接了所有的交互逻辑,交互的复杂度转变成了中介者的复杂度,中介者类会变得越来越庞大和复杂,以至于难以维护。
中介者出问题会导致多个使用者同时出问题。
4. 应用场景
一组对象以定义良好但复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
想通过一个中间类来封装多个类中的行为,同时又不想生成太多的子类。



