组件协作类设计模式

  • 1 分类含义
  • 2 模板方法模式
    • 2.1 动机
    • 2.2 场景
      • 2.2.1实现方式一(客户端控制主流程)
      • 2.2.2 实现方式二(模板方法模式)
    • 2.3 概念
    • 2.4 要点总结
  • 3 策略模式
    • 3.1 动机
    • 3.2 场景
      • 3.2.1 抽象策略
      • 3.2.2 中国税法实现
      • 3.2.3 美国税法实现
      • 3.2.4 客户端调用
    • 3.3 什么是复用【题外话】
    • 3.4 模式定义
    • 3.5 要点总结
  • 4 观察者模式
    • 4.1 动机
    • 4.2 场景
      • 4.2.1 JDK观察者
      • 4.2.2 JDK被观察者
      • 4.2.3 实现User观察者
      • 4.2.4 实现作者被观察者
      • 4.2.5 客户端调用
    • 4.3 观察者模式要点

1 分类含义

现代软件专业分工之后的第一个结果是框架与应用程序的划分,组件协作模式通过晚期绑定,来实现框架与应用之间的松耦合,组件协作模式就是常用于这类场景的模式。

2 模板方法模式

2.1 动机

在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架于应用之间的关系)需求无法和任务的整体结构同时实现。

如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的的变化或者晚期实现的需求?

2.2 场景

如某个业务需要步骤一、步骤二、步骤三、步骤四、步骤五 五个步骤完成,但是步骤一三四是框架编写的固定处理程序,步骤二五需要后期的应用程序编写人员来编写实现。

2.2.1实现方式一(客户端控制主流程)

方案一:接口(或抽象类)定义步骤一二三四五的方法,并实现一三四的方法,方法的实现和步骤的掌控交给实现类(或子类)

public class TemplateMethod {/*** 类库实现者开发*/interface Lib {default void step1() {//实现}/*** 晚绑定*/void step2();default void step3() {//实现}default void step4() {//实现}/*** 晚绑定*/void step5();}/*** 客户端*/class Client implements Lib {@Overridepublic void step2() {//实现}@Overridepublic void step5() {//实现}/*** 需求*/public void demand() {//控制步骤step1();step2();step3();step3();step4();step5();}}
}

缺点: 客户端使用者把控稳定的步骤一至步骤五的操作,容易提高代码出错的概率;当变化多的时候,demand()方法复用率低(其次,你也可以抽方法,虽然有更好的复用方式)

2.2.2 实现方式二(模板方法模式)

public class TemplateMethod {/*** 类库实现者开发*/interface Lib {default void step1() {//实现}//变化-->多态void step2();default void step3() {//实现}default void step4() {//实现}/*** 变化-->多态*/void step5();/*** 整体结构(模板方法模式)*/default void demand(){step1();step2();step3();step3();step4();step5();}}public static void main(String[] args) {Lib lib = new Lib() {@Overridepublic void step2() {//实现}@Overridepublic void step5() {//实现}};lib.demand();}
}

2.3 概念

定义一个操作中的算法的骨架,而将一些变化的步骤延迟到子类中,模板方法模式使得子类可以复用一个算法的结构,并且同时可重写算法的某些特定步骤来应对这个步骤的变化。

2.4 要点总结

  • 模板方法模式是一个非常基础性的设计模式,在面向对象系统种有着大量的应用,它用抽象方法的多态性为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构
  • 除了可以灵活应对子步骤的变化外,不要调用我,让我来调用你的反向控制结构是模板方法模式的典型应用。
  • 在具体实现方面,被模板方法调用的虚方法可以有具体实现,也可以没有任何实现。

3 策略模式

3.1 动机

在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到一个对象中,将会使对象变得异常复杂且不易适应变化。

如何在运行时根据需要透明的更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

3.2 场景

现在要做一个税率计算软件,要支持很多国家的税率计算,而且在往后可能还需要支持更多的国家,怎么利用策略模式来实现这样的需求?

3.2.1 抽象策略

package com.example.demo.strategy;import java.math.BigDecimal;public interface TaxStrategy {BigDecimal calculateTax(BigDecimal money);}

3.2.2 中国税法实现

package com.example.demo.strategy.impl;import com.example.demo.strategy.TaxStrategy;import java.math.BigDecimal;public class ChineseTaxStrategy implements TaxStrategy {@Overridepublic BigDecimal calculateTax(BigDecimal money) {// 按中国的税法计算应缴税额return money.multiply(new BigDecimal("0.07"));}
}

3.2.3 美国税法实现

package com.example.demo.strategy.impl;import com.example.demo.strategy.TaxStrategy;import java.math.BigDecimal;public class USATaxStrategy implements TaxStrategy {@Overridepublic BigDecimal calculateTax(BigDecimal money) {return money.multiply(new BigDecimal("0.08"));}
}

3.2.4 客户端调用

package com.example.demo.strategy;import com.example.demo.strategy.impl.USATaxStrategy;import java.math.BigDecimal;public class PayTax {public static void main(String[] args) {// 这里的策略实现类一般由工厂生成payTax(new USATaxStrategy(), new BigDecimal("10"));}public static void payTax(TaxStrategy taxStrategy, BigDecimal money){// 保证了主流程不变,变化全部在工厂和新增的类里面BigDecimal tax = taxStrategy.calculateTax(money);System.out.println("缴纳税额:" + tax);}
}

3.3 什么是复用【题外话】

策略模式往往也可以通过if else不同的分支来实现,但是这样做的坏处是没有做到代码的复用,我们通常认为,在代码编译时这个文件编程生成的字节码没有变化才算作复用,因为只有编译内容完全没变,才能保证不会影响之前所书写的代码。

3.4 模式定义

定义一系列算法,把他们一个个封装起来,并且是他们可以相互替换。该模式使得算法可以独立于使用它的客户程序而变化。

3.5 要点总结

  • 策略模式及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便的根据需要在各个算法之间进行切换;
  • 策略模式能够一定程度上消除条件判断语句
  • 策略如果没有状态或实例变量的话,可以全局使用同一个对象。

4 观察者模式

4.1 动机

在软件构建过程中,我们需要为某些对象建立一种通知依赖关系,一个对象的状态发生改变,所有的依赖对象将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好的抵御变化。

4.2 场景

实现作者发布文章后订阅该作者的用户收到作者发布的通知

4.2.1 JDK观察者

JDK有提供一个观察者的简单抽象,先看看JDK提供的观察者


package java.util;public interface Observer {void update(Observable o, Object arg);
}

很简单的一个接口,没什么好说的。

4.2.2 JDK被观察者


public class Observable {private boolean changed = false;private Vector<Observer> obs;/** Construct an Observable with zero Observers. */public Observable() {obs = new Vector<>();}public synchronized void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.addElement(o);}}public synchronized void deleteObserver(Observer o) {obs.removeElement(o);}public void notifyObservers() {notifyObservers(null);}public void notifyObservers(Object arg) {/** a temporary array buffer, used as a snapshot of the state of* current Observers.*/Object[] arrLocal;synchronized (this) {/* We don't want the Observer doing callbacks into* arbitrary code while holding its own Monitor.* The code where we extract each Observable from* the Vector and store the state of the Observer* needs synchronization, but notifying observers* does not (should not).  The worst result of any* potential race-condition here is that:* 1) a newly-added Observer will miss a*   notification in progress* 2) a recently unregistered Observer will be*   wrongly notified when it doesn't care*/if (!changed)return;arrLocal = obs.toArray();clearChanged();}for (int i = arrLocal.length-1; i>=0; i--)((Observer)arrLocal[i]).update(this, arg);}public synchronized void deleteObservers() {obs.removeAllElements();}protected synchronized void setChanged() {changed = true;}protected synchronized void clearChanged() {changed = false;}public synchronized boolean hasChanged() {return changed;}public synchronized int countObservers() {return obs.size();}
}

大致就是设置了一个状态,和观察者数组,观察者数据里面维护了观察对象,调用notify…方法的时候,如果状态为true,则会循环调用被维护的观察对象的update方法。

4.2.3 实现User观察者

package com.example.demo.observer;import java.util.Observable;
import java.util.Observer;public class SubscribeUser implements Observer {private final String nickName;public SubscribeUser(String nickName) {this.nickName = nickName;}@Overridepublic void update(Observable o, Object arg) {Author author = (Author) o;System.out.println(nickName + "接收到来自" + author.getAuthorName() + "的文章" + arg);}}

这个类仅仅是实现了Observer 接口,为了方便展示,我们添加了一个昵称字段,在update方法中打印了这条通知消息

4.2.4 实现作者被观察者

package com.example.demo.observer;import java.util.Observable;
import java.util.Observer;public class Author extends Observable {private final String authorName;public Author(String authorName) {this.authorName = authorName;}public void setObserver(Observer[] observers){for (Observer observer : observers) {addObserver(observer);}}public String getAuthorName() {return authorName;}public void publishNewArticle(String articleTitle){System.out.println(this.authorName + "发布了文章" + articleTitle);setChanged();notifyObservers(articleTitle);clearChanged();}}

同样的,为了方便展示给了一个名称,天界了一个设置观察者的方法,发布新文章的方法,在新文章中调用了JDK被观察者的set状态,通知观察者后清除状态。

4.2.5 客户端调用

package com.example.demo.observer;public class Main {public static void main(String[] args) {Author author = new Author("天蚕土豆");SubscribeUser[] subscribeUsers = {new SubscribeUser("贺伟"),new SubscribeUser("梁少波")};author.setObserver(subscribeUsers);author.publishNewArticle("《斗破苍穹》");author.publishNewArticle("《大主宰》");}}

4.3 观察者模式要点

  • 使用面向对象的抽象,观察者模式可以是我们可以独立的改变观察者与被观察者,从而使二者的依赖关系达到松耦合。
  • 目标发送通知时,无需指定观察者,通知会自动传播
  • 观察者模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一份重要组成部分。

二、组件协作类设计模式相关推荐

  1. C++设计模式 之 “组件协作”模式:Template Method、Strategy、Observer

    "组件协作"模式: #现代软件专业分工之后的第一个结果是"框架与应用程序的划分","组件协作"模式通过晚期绑定,来实现框架与应用程序之间的松 ...

  2. 李建忠设计模式之“组件协作”模式

    文章目录 模板方法模式(Template Method) 定义 动机 结构图 代码 要点 总结 策略模式(Strategy) 定义 动机 结构图 代码 要点 总结 观察者模式(Observer/Eve ...

  3. 李建忠设计模式-组件协作模式-模板方法模式

    目录 1.前言 2.模板方法模式(Template Method) 1.动机 2.例子 3.定义 1.结构图 2.模板方法模式适用情形 3.模式特点 参考 1.前言 现代软件专业分工后的第一个结果是& ...

  4. 设计模式(二)23种设计模式

    设计模式(二)23种设计模式 文章目录 设计模式(二)23种设计模式 组件协作模式 策略模式 观察者模式 单一职责模式 Decorator模式 Bridge模式 对象创建模式 Factory Meth ...

  5. Python、设计原则和设计模式-创建类设计模式

    Python.设计原则和设计模式 前言 程序的目标:高内聚 低耦合 有哪些设计原则 设计原则是「高内聚.低耦合」的具体落地. 单一职责原则要求在软件系统开发.设计中,一个类只负责一个功能领域的相关职责 ...

  6. 软件工程第二次二人协作项目 3D俄罗斯方块

    开发背景: 完成软件工程任务,提高自己解决问题的实际能力,适应二人协作开发的模式,互助进取. 本次作业将完成一个3D版本的俄罗斯方块的小游戏开发. 开发组员: 张羿  2012211841  宋浩达 ...

  7. 创建类设计模式简洁介绍

    一 闲谈 最近在复习设计模式,很多模式让说名字,可能记不住,但是日常开发中用的挺多的,有时候形成一种习惯.这一轮学习先把模式简化下,以前学什么总讲究完备,好像少了点很重要似的,其实很多时候应用的是基础 ...

  8. “组件协作”模式----策略模式(Strategy Pattern)

    文章目录 1."组件协作"模式 2.策略模式动机(Motivation) 3.问题引入 4.商场收银系统1.0 5. 使用简单工厂模式 6.简单工厂模式的缺陷 7. 简单工厂模式和 ...

  9. onclick=两个函数_[译]React函数组件和类组件的差异

    [译]React函数组件和类组件的差异 原文: https://overreacted.io/how-are-function-components-different-from-classes/ 在 ...

最新文章

  1. ASP.NET简化编辑界面 V3
  2. 职业梦想是计算机的英语作文,我的梦想职业英语作文
  3. 皮一皮:现在的年轻人不得了吖...
  4. WMS Schema
  5. mysql 用户名中主机$_phpMyAdmin 尝试连接到 MySQL 服务器,但服务器拒绝连接。您应当检查配置文件中的主机、用户名和密码,...
  6. 5.Loops and List Comprehensions
  7. Jupyter Notebook数据科学高效技巧
  8. 小白学算法:买卖股票的最佳时机!
  9. 查看Ubuntu中的ip地址
  10. AI 人才缺失催生跨境猎头:人才年薪高达 300 万,猎头直赚 100 万
  11. 爬虫基础以及 re,BeatifulSoup,requests模块使用
  12. html文字居中单词,html文字居中
  13. Kubernetes(k8s)从入门到精通
  14. 基于python+OpenCV的车牌号码识别
  15. Markdown / KaTex数学公式汇总
  16. 《小强升职记》读后感
  17. PartyOK酒水知识大全
  18. 探索<赛博朋克>风格游戏美术
  19. Foundation5(十五)
  20. JS+HTML5的Canvas画图模拟太阳系运转

热门文章

  1. oracle10 升级为11,Oracle10.2.0.4升级至Oracle11.2.0.3错误手记一则
  2. 【DSP】DTMF 信号的编码和解码
  3. java获取oracle自增_oracle 自增变量设置
  4. PCB生产工艺 | 第七道主流程之阻焊
  5. html5视频播放自动全屏
  6. php鼠标点击事件,javascript模拟鼠标点击事件的实例代码
  7. java-php-python-ssm停车场收费管理系统计算机毕业设计
  8. PhotoShopCS5
  9. 计算机丢失cxplus.dll,pyinstaller打包cx_Oracle库问题处理记录
  10. 计算机辅助园林设计作业,《计算机辅助园林设计B - usleducn.DOC