文章目录

  • 观察者模式
  • 模板模式
    • 模板模式与回调
  • 策略模式
    • 定义
    • 创建
    • 使用
    • 如何避免掉冗长的if-else|switch分支判断代码?
  • 职责链模式
    • 定义
    • 实现
      • 第一种
      • 第二种(其实就是使用数组实现而已)
    • 应用场景
  • 迭代器模式
    • 实现
    • 使用场景和优势
  • 状态模式

观察者模式

极客时间《设计模式之美》笔记—观察者模式

模板模式

模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。

原理很简单,代码实如下所示。templateMethod()函数定义为final,是为了避免子类重写它。method1()和method2()定义为abstract,是为了强迫子类去实现。

public abstract class AbstractClass {// 1. 有些方法又严禁子类实现public final void templateMethod() {//...method1();//...method2();//...}// 2. 有些逻辑父类做不了主,就交给子类,强迫子类去实现。protected abstract void method1();//3. 父类实现一些公用的逻辑private void parentFun() {System.out.println("parent function");System.out.println("step 1 ");System.out.println("step 2 ");System.out.println("step 3 ");//4. 有些逻辑再直接交给子类去做,父类直接定义逻辑模板method1();}protected abstract void method2();// 5. 有些逻辑父类可以做一部分,最做的就做,但是最好是由子类实现。protected void setUp() throws Exception {// 父类设置}
}public class ConcreteClass1 extends AbstractClass {@Overrideprotected void method1() {//...}@Overrideprotected void method2() {//...}
}public class ConcreteClass2 extends AbstractClass {@Overrideprotected void method1() {//...}@Overrideprotected void method2() {//...}
}// 在这里使用AbstractClass demo = ConcreteClass1();demo.templateMethod();

模板模式有两大作用:复用和扩展。其中,复用指的是,所有的子类可以复用父类中提供的模板方法的代码。扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能。

模板模式与回调

策略模式

定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

我们知道,工厂模式是解耦对象的创建和使用,观察者模式是解耦观察者和被观察者。策略模式跟两者类似,也能起到解耦的作用,不过,它解耦的是策略的定义、创建、使用这三部分。接下来,我就详细讲讲一个完整的策略模式应该包含的这三个部分。

定义

public interface Strategy {void algorithmInterface();
}public class ConcreteStrategyA implements Strategy {@Overridepublic void  algorithmInterface() {//具体的算法...}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void  algorithmInterface() {//具体的算法...}
}

创建

public class StrategyFactory {private static final Map strategies = new HashMap<>();static {strategies.put("A", new ConcreteStrategyA());strategies.put("B", new ConcreteStrategyB());}public static Strategy getStrategy(String type) {if (type == null || type.isEmpty()) {throw new IllegalArgumentException("type should not be empty.");}return strategies.get(type);}
}

使用

// 策略接口:EvictionStrategy
// 策略类:LruEvictionStrategy、FifoEvictionStrategy、LfuEvictionStrategy...
// 策略工厂:EvictionStrategyFactorypublic class UserCache {private Map cacheData = new HashMap<>();private EvictionStrategy eviction;public UserCache(EvictionStrategy eviction) {this.eviction = eviction;}//...
}// 运行时动态确定,根据配置文件的配置决定使用哪种策略
public class Application {public static void main(String[] args) throws Exception {EvictionStrategy evictionStrategy = null;Properties props = new Properties();props.load(new FileInputStream("./config.properties"));String type = props.getProperty("eviction_type");evictionStrategy = EvictionStrategyFactory.getEvictionStrategy(type);UserCache userCache = new UserCache(evictionStrategy);//...}
}// 非运行时动态确定,在代码中指定使用哪种策略
public class Application {public static void main(String[] args) {//...EvictionStrategy evictionStrategy = new LruEvictionStrategy();UserCache userCache = new UserCache(evictionStrategy);//...}
}

如何避免掉冗长的if-else|switch分支判断代码?

//原代码
public class OrderService {public double discount(Order order) {double discount = 0.0;OrderType type = order.getType();if (type.equals(OrderType.NORMAL)) { // 普通订单//...省略折扣计算算法代码} else if (type.equals(OrderType.GROUPON)) { // 团购订单//...省略折扣计算算法代码} else if (type.equals(OrderType.PROMOTION)) { // 促销订单//...省略折扣计算算法代码}return discount;}
}

重构后:

// 策略的定义
public interface DiscountStrategy {double calDiscount(Order order);
}
// 省略NormalDiscountStrategy、GrouponDiscountStrategy、PromotionDiscountStrategy类代码...// 策略的创建
public class DiscountStrategyFactory {private static final Map strategies = new HashMap<>();static {strategies.put(OrderType.NORMAL, new NormalDiscountStrategy());strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy());strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy());}public static DiscountStrategy getDiscountStrategy(OrderType type) {return strategies.get(type);}
}// 策略的使用
public class OrderService {public double discount(Order order) {OrderType type = order.getType();DiscountStrategy discountStrategy = DiscountStrategyFactory.getDiscountStrategy(type);return discountStrategy.calDiscount(order);}
}

但是,如果业务场景需要每次都创建不同的策略对象,我们就要用另外一种工厂类的实现方式了。具体的代码如下所示:

public class DiscountStrategyFactory {public static DiscountStrategy getDiscountStrategy(OrderType type) {if (type == null) {throw new IllegalArgumentException("Type should not be null.");}if (type.equals(OrderType.NORMAL)) {return new NormalDiscountStrategy();} else if (type.equals(OrderType.GROUPON)) {return new GrouponDiscountStrategy();} else if (type.equals(OrderType.PROMOTION)) {return new PromotionDiscountStrategy();}return null;}
}

这种实现方式相当于把原来的if-else分支逻辑,从OrderService类中转移到了工厂类中,实际上并没有真正将它移除。

职责链模式

模板模式、策略模式,今天,我们来学习职责链模式。这三种模式具有相同的作用:复用和扩展,在实际的项目开发中比较常用,特别是框架开发中,我们可以利用它们来提供框架的扩展点,能够让框架的使用者在不修改框架源码的情况下,基于扩展点定制化框架的功能。

定义

将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过A处理器处理,然后再把请求传递给B处理器,B处理器处理完后再传递给C处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式

实现

第一种

public abstract class Handler {protected Handler successor = null;public void setSuccessor(Handler successor) {this.successor = successor;}public abstract void handle();
}public class HandlerA extends Handler {@Overridepublic void handle() {boolean handled = false;//真实业务逻辑if (!handled && successor != null) {successor.handle();}}
}public class HandlerB extends Handler {@Overridepublic void handle() {boolean handled = false;//真实业务逻辑//注意下面的这个设置其实是与业务无关的,所以完全可以提取出来,写为一个模板模式!!!if (!handled && successor != null) {successor.handle();}}
}public class HandlerChain {private Handler head = null;private Handler tail = null;public void addHandler(Handler handler) {handler.setSuccessor(null);if (head == null) {head = handler;tail = handler;return;}tail.setSuccessor(handler);tail = handler;}public void handle() {if (head != null) {head.handle();}}
}// 使用举例
public class Application {public static void main(String[] args) {HandlerChain chain = new HandlerChain();//有顺序的处理器链条chain.addHandler(new HandlerA());chain.addHandler(new HandlerB());chain.handle();}
}

重构为模板模式后:

public abstract class Handler {protected Handler successor = null;public void setSuccessor(Handler successor) {this.successor = successor;}public final void handle() {boolean handled = doHandle();if (successor != null && !handled) {successor.handle();}}protected abstract boolean doHandle();
}public class HandlerA extends Handler {@Overrideprotected boolean doHandle() {boolean handled = false;//...return handled;}
}public class HandlerB extends Handler {@Overrideprotected boolean doHandle() {boolean handled = false;//...return handled;}
}// HandlerChain和Application代码不变

第二种(其实就是使用数组实现而已)

public interface IHandler {boolean handle();
}public class HandlerA implements IHandler {@Overridepublic boolean handle() {boolean handled = false;//...return handled;}
}public class HandlerB implements IHandler {@Overridepublic boolean handle() {boolean handled = false;//...return handled;}
}public class HandlerChain {private List handlers = new ArrayList<>();public void addHandler(IHandler handler) {this.handlers.add(handler);}public void handle() {for (IHandler handler : handlers) {boolean handled = handler.handle();if (handled) {break;}}}
}// 使用举例
public class Application {public static void main(String[] args) {HandlerChain chain = new HandlerChain();chain.addHandler(new HandlerA());chain.addHandler(new HandlerB());chain.handle();}
}

应用场景

  • 符合开闭原则
  • 将大块代码逻辑拆分成函数,将大类拆分成小类,是应对代码复杂性的常用方法

迭代器模式

用来遍历集合对象。这里说的“集合对象”也可以叫“容器”“聚合对象”,实际上就是包含一组对象的对象,比如数组、链表、树、图、跳表。迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一

迭代器是用来遍历容器的,所以,一个完整的迭代器模式一般会涉及容器和容器迭代器两部分内容。为了达到基于接口而非实现编程的目的,容器又包含容器接口、容器实现类,迭代器又包含迭代器接口、迭代器实现类。

实现

// 接口定义
public interface Iterator {boolean hasNext();void next();E currentItem();
}
public class ArrayIterator implements Iterator {private int cursor;private ArrayList arrayList;// 返回一个迭代器类public Iterator iterator() {return new ArrayIterator(this);}@Overridepublic boolean hasNext() {return cursor != arrayList.size(); //注意这里,cursor在指向最后一个元素的时候,hasNext()仍旧返回true。}@Overridepublic void next() {cursor++;}@Overridepublic E currentItem() {if (cursor >= arrayList.size()) {throw new NoSuchElementException();}return arrayList.get(cursor);}
}public class Demo {public static void main(String[] args) {ArrayList names = new ArrayList<>();names.add("xzg");names.add("wang");names.add("zheng");Iterator iterator = names.iterator();while (iterator.hasNext()) {System.out.println(iterator.currentItem());iterator.next();}}
}

总结下来就三句话:迭代器中需要定义hasNext()、currentItem()、next()三个最基本的方法。待遍历的容器对象通过依赖注入传递到迭代器类中。容器通过iterator()方法来创建迭代器。

使用场景和优势

  • 对于类似数组和链表这样的数据结构,遍历方式比较简单,直接使用for循环来遍历就足够了。但是,对于复杂的数据结构(比如树、图)来说,有各种复杂的遍历方式。比如,树有前中后序、按层遍历,图有深度优先、广度优先遍历等等。如果由客户端代码来实现这些遍历算法,势必增加开发成本,而且容易写错。如果将这部分遍历的逻辑写到容器类中,也会导致容器类代码的复杂性。
    前面也多次提到,应对复杂性的方法就是拆分。我们可以将遍历操作拆分到迭代器类中。比如,针对图的遍历,我们就可以定义DFSIterator、BFSIterator两个迭代器类,让它们分别来
    实现深度优先遍历和广度优先遍历
  • 创建多个不同的迭代器,同时对同一个容器进行遍历而互不影响(这个好像创建多个for循环遍历也能做到,当然其底层就是根绝迭代器实现的嘛)
  • 容器和迭代器都提供了抽象的接口,方便我们在开发的时候,基于接口而非具体的实现编程。当需要切换新的遍历算法的时候,比如,从前往后遍历链表切换成从后往前遍历链表,客户端代码只需要将迭代器类从LinkedIterator切换为ReversedLinkedIterator即可,其他代码都不需要修改。除此之外,添加新的遍历算法,我们只需要扩展新的迭代器类,也更符合开闭原则。
  • 不支持增删元素,如果增删元素之后就会让遍历报错,遍历操作会直接抛出运行时异常。

状态模式

极客时间《设计模式之美》笔记—状态模式

《设计模式之美》笔记---行为型设计模式相关推荐

  1. 设计模式之美笔记11

    记录学习王争的设计模式之美 课程 笔记和练习代码,以便回顾复习,共同进步 文章目录 门面模式 门面模式的原理和实现 门面模式的应用场景举例 1. 解决易用性问题 2. 解决性能问题 3. 解决分布式事 ...

  2. 设计模式之美---常用创建型模式

    目录 单例模式 如何实现一个单例? 处理资源访问冲突 表示全局唯一类 单例的几种实现方式 实现一个线程唯一的单例模式 实现一个集群环境下的单例 工厂模式 简单工厂 工厂方法 抽象工厂 实现一个DI(D ...

  3. Java设计模式(二)创建型设计模式

    文章目录 三 创建型设计模式 3.1 单例设计模式 3.1.1 饿汉式(线程安全) 3.1.2 懒汉式(线程不安全) 3.1.3 优缺点 3.1.4 补充 3.1.5 框架中的使用 3.1.4.1 S ...

  4. c++设计模式详解_创建型设计模式

    设计模式(设计原则演化而来) 一.定义 设计模式是软件开发过程中,经过验证的,用于在特定环境下重复出现的,特定问题的解决方案.简单来说,就是特定环境下的固定编程套路. 1.1 解决了什么问题? 只需要 ...

  5. JAVA设计模式第二讲:创建型设计模式

    设计模式(design pattern)是对软件设计中普遍存在的各种问题,所提出的解决方案.本文以面试题作为切入点,介绍了设计模式的常见问题.我们需要掌握各种设计模式的原理.实现.设计意图和应用场景, ...

  6. 《设计模式》读书笔记——创建型模式

    设计模式 创建模式 定义: 创建型模式抽象了实例化过程.他们帮助一个系统独立于如何创建.组合和表示它的那些对象 一个类创建型模式使用继承改变被实例化的类,而一个对象创建模式是将实例化委托给另一个对象 ...

  7. 设计模式之美(4)-创建型-建造者模式

    Builder模式,中文翻译为建造者模式或者构建者模式,也有人叫它生成器模式. 建造者模式原理和代码非常简单, 难点在于应用场景.比如直接使用构造函数或者配合set方法就能创建对象,为什么还需要建造者 ...

  8. 设计模式一网打尽,40余篇文章带你领略设计模式之美

    文章末尾附带GitHub开源下载地址. 该文章的最新版本已迁移至个人博客[比特飞],单击链接 设计模式一网打尽,40余篇文章带你领略设计模式之美 | .Net中文网 访问. 设计模式概述 20世纪80 ...

  9. 《设计模式》学习笔记整理手册

    文章目录 一.GoF设计模式的分类 1.1 创建型 1.2 结构型 1.3 行为型 二.设计原则概述 2.1 面向对象设计原则概述: 2.2 单一职责原则 2.3 开闭原则 2.4 里氏代换原则 2. ...

最新文章

  1. android alpha不起作用,API 28(P)的Android设计支持库不起作用
  2. scrapy安装出错
  3. 【excel】vlookup
  4. python识别图片数字traceract_如何将图形调用打印为树?
  5. 【Android Developers Training】 6. 配置Action Bar
  6. chrome 悬停大图插件_Google Chrome浏览器的悬停卡:我不想要的我最喜欢的新东西
  7. 海信CAS计算机辅助手术系统,计算机辅助手术系统(CAS)
  8. 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)签到题K Co-prime Permutation,L Let‘s Play Curling
  9. 如何学习Android系统源码
  10. java鬼吹灯搬山法杖_《鬼吹灯》里有4个流派,搬山就是鹧鸪哨,那么发丘谁当主呢?...
  11. android程序 美食分享,下厨房Android产品分析
  12. android 蒲公英 类似平台,Jenkins之android APP打包上传蒲公英平台
  13. 写诗软件这里为什么会如此成功?
  14. 高德地图自己录制导航声音备份及恢复方法
  15. MySQL性能指标TPS+QPS+IOPS压测
  16. IT公司招聘人才新标准:不需高学历但要绝顶聪明
  17. SSL证书背后的加密技术--非对称加密和对称加密
  18. React Native 安卓人民币符号显示异常问题解决
  19. 【Netty系列_3】Netty源码分析之服务端channel
  20. mac npm install XX权限权限报错的完美解决方法

热门文章

  1. 浅析ReentLock的使用
  2. swin-Transformer论文详解
  3. 【Dos】Dos常用命令
  4. 【深度学习】RGB图像的内存排列方式及HWC和CHW格式解析
  5. MySQL怎么运行的系列(十)Innodb中的锁:记录锁、临键锁、间隙锁、意向锁
  6. 中国电商早已做到的服务,美国电商如今才达成,中国互联网引领全球创新
  7. 通过autorun.inf和autorun.ico设置U盘识别图标
  8. AIQ - deeplearning.ai 全套吴恩达老师的深度学习课程笔记及资源在线阅读
  9. 问题 A: [入门OJ]买水果(初中生请多多指教)
  10. 女儿被继母杀害因不见尸骨疑犯被放 母亲讨公道