觉得不错请按下图操作,掘友们,哈哈哈!!!

JYM 设计模式系列- 责任链模式,装饰模式,让你的代码更优雅!!!

概述规划形式分类

整体来说规划形式分为三大类:

  • 创立型形式,共五种:工厂办法形式、笼统工厂形式、单例形式、制作者形式、原型形式。

  • 结构型形式,共七种:适配器形式、装修器形式、署理形式、外观形式、桥接形式、组合形式、享元形式。

  • 行为型形式,共十一种:战略形式、模板办法形式、观察者形式、迭代子形式、职责链形式、指令形式、备忘录形式、状况形式、访问者形式、中介者形式、解释器形式。

一:职责链形式

1.1 名词解释:

职责链形式是一种行为规划形式,允许你将恳求沿着处理者链进行发送。收到恳求后,每个处理者均可对恳求进行处理,或将其传递给链上的下个处理者。职责链形式的中心是处理一组服务中的先后执行处理联系。

职责链形式能够让各个服务模块愈加清晰,而每一个模块能够经过next的办法进行获取。而每一个next是由承继的统一笼统类完成的,终究一切类的职责能够动态的进行编列运用,编列的进程能够做成可装备化。

在运用职责链时,如果场景比较固定,可写死到代码中进行初始化。但如果事务场景经常改动能够做成xml装备的办法进行处理,也能够保存到数据库中进行初始化操作。

实践的事务中在运用职责链时会进行一系列的包装,经过把不同的职责节点进行拼装,构成一条完整事务的职责链。

1.2 长处:

职责链形式很好的处理单一职责和开闭准则,简略耦合也使方针联系愈加清晰,并且外部的调用方并不需求联系职责链是如何处理的。

1.3职责链形式结构

  • 处理者
    声明晰一切详细处理者的通用接口,该接口通常仅包括单个办法用于恳求处理,但有时其还会包括一个设置链上下处理者的办法。
  • 根底处理者 是一个可选的类,你能够将一切处理者共用的样本代码放置在其间。(通常情况下,该类界说了一个保存关于下个处理者引证的成员变量。客户端可经过将处理者的构造函数或设定办法来创立链。该类还能够完成默认的处理行为,确定下个处理者存在后再将恳求传递给它。)
  • 详细处理者 包括处理恳求的实践代码。每个处理者接纳到恳求后,都必须决议是否进行处理,或许说是否沿着链传递恳求。
  • 客户端
    可根据程序逻辑一次性或许动态的生成链。

1.4 适用场景

  • 当程序需求运用不同办法处理不同种类恳求,并且恳求类型和次序预先未知时。
  • 事务逻辑必须按次序执行多个处理者时。
  • 处理者及其次序必须在运行时进行改动,能够运用职责链形式。

1.5 完成办法

  • 声明处理者接口并描绘恳求处理办法的签名
  • 能够根据处理者接口创立笼统处理者基类(需求一个成员变量来存储指向链上下个处理者的引证)
  • 创立详细的处理者子类并完成其处理办法。(每个处理者在接纳到恳求后都必须做两个决议:1、是否自行处理恳求;2、是否将该恳求沿着链进行传递。)
  • 客户端可自行拼装链,或许从其他方针处获得预先拼装好的链。
  • 客户端可触发链中的任意处理者,而不仅仅是第一个。恳求将经过链进行传递,直至某个处理者回绝继续传递或许恳求到达链尾。

1.6 上demo

JYM 设计模式系列- 责任链模式,装饰模式,让你的代码更优雅!!!

RequestHandler :恳求处理器

public interface RequestHandler {
  boolean canHandleRequest(Request req);
  int getPriority();
  void handle(Request req);
  String name();
}

Request:

public class Request {
  /**
   * 此恳求的类型,由链中的每个项目运用以检查它们是否应该或能够处理
   * 这个特殊要求
   */
  private final RequestType requestType;
  /**
   * 恳求的描绘
   */
  private final String requestDescription;
  /**
   * 指示恳求是否已处理。恳求只能将状况从未处理切换到
   * 已处理,无法“取消处理”恳求
   */
  private boolean handled;
  /**
   * 创立给定类型和随附描绘的新恳求。
   *
   * @param requestType        The type of request
   * @param requestDescription The description of the request
   */
  public Request(final RequestType requestType, final String requestDescription) {
    this.requestType = Objects.requireNonNull(requestType);
    this.requestDescription = Objects.requireNonNull(requestDescription);
  }
  /**
   * 获取恳求的描绘。
   *
   * @回来恳求的人可读描绘
   */
  public String getRequestDescription() {
    return requestDescription;
  }
  /**
   * G获取此恳求的类型,由指令链中的每个人运用以检查他们是否应该
   * 或许能够处理这个特定的恳求
   *
   * @return The request type
   */
  public RequestType getRequestType() {
    return requestType;
  }
  /**
   * 将恳求标记为已处理
   */
  public void markHandled() {
    this.handled = true;
  }
  /**
   * 指示是否处理此恳求
   *
   * @return <tt>true</tt> when the request is handled, <tt>false</tt> if not
   */
  public boolean isHandled() {
    return this.handled;
  }
  @Override
  public String toString() {
    return getRequestDescription();
  }
}

RequestType:恳求枚举类

public enum RequestType {
  DEFEND_CASTLE, //防御城堡
  TORTURE_PRISONER,//酷刑罪犯
  COLLECT_TAX //收税
}

OrcCommander:兽人指挥官

@Slf4j
public class OrcCommander implements RequestHandler {
  @Override
  public boolean canHandleRequest(Request req) {
    return req.getRequestType() == RequestType.DEFEND_CASTLE;
  }
  @Override
  public int getPriority() {
    return 2;
  }
  @Override
  public void handle(Request req) {
    req.markHandled();
    LOGGER.info("{} handling request "{}"", name(), req);
  }
  @Override
  public String name() {
    return "Orc commander";
  }
}

OrcKing: 宣布由链处理的恳求

public class OrcKing {
  private List<RequestHandler> handlers;
  public OrcKing() {
    buildChain();
  }
  private void buildChain() {
    handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier());
  }
  /**
   * Handle request by the chain.
   */
  public void makeRequest(Request req) {
    handlers
        .stream()
        .sorted(Comparator.comparing(RequestHandler::getPriority))
        .filter(handler -> handler.canHandleRequest(req))
        .findFirst()
        .ifPresent(handler -> handler.handle(req));
  }
}

OrcOfficer:兽人军官

@Slf4j
public class OrcOfficer implements RequestHandler {
  @Override
  public boolean canHandleRequest(Request req) {
    return req.getRequestType() == RequestType.TORTURE_PRISONER;
  }
  @Override
  public int getPriority() {
    return 3;
  }
  @Override
  public void handle(Request req) {
    req.markHandled();
    LOGGER.info("{} handling request "{}"", name(), req);
  }
  @Override
  public String name() {
    return "Orc officer";
  }
}

OrcSoldier:兽人士兵

@Slf4j
public class OrcSoldier implements RequestHandler {
  @Override
  public boolean canHandleRequest(Request req) {
    return req.getRequestType() == RequestType.COLLECT_TAX;
  }
  @Override
  public int getPriority() {
    return 1;
  }
  @Override
  public void handle(Request req) {
    req.markHandled();
    LOGGER.info("{} handling request "{}"", name(), req);
  }
  @Override
  public String name() {
    return "Orc soldier";
  }
}

程序进口:

public class App {
  /**
   * Program entry point.
   *
   * @param args command line args
   */
  public static void main(String[] args) {
    var king = new OrcKing();
    king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle 保卫城堡"));
    king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner 酷刑罪犯"));
    king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax 征税"));
  }
}

在这个例子中,咱们将恳求处理程序 RequestHandler组织成一个链,其间 每个处理程序都有时机轮流处理恳求。这儿国王 OrcKing宣布恳求,军事兽人 OrcCommander, OrcOfficer, OrcSoldier 形成处理程序链。

二:装修形式

2.1 什么是装修形式解释:

装修形式又叫包装形式(Wrapper)。装修形式是以对客户端通明的办法扩展方针的功用,是承继联系的一种代替计划。

  • 装修形式以对客户通明的办法动态的给方针附加更多的职责,换言之客户并不会觉得方针在装修前和装修后有什么区别。
  • 装修形式能够在不增加子类的情况下,将方针的功用扩展。
  • 装修形式把客户端的调用委派到被装修类,装修形式的关键在于这种功用的扩展是通明的。
  • 装修形式是在不用改动原类文件和运用承继的情况下,动态的扩展一个方针的功用,它是经过创立一个包装方针,也就是装修来包裹真是的方针。

2.2 装修形式的组成

  • 笼统构件人物(Component):给出一个笼统接口,已规范准备接受附加职责的方针。
  • 详细构件人物(Concrete Component):界说一个即将接纳附加职责的类。
  • 装修人物(Decrator):持有一个构建人物方针的引证,并界说一个与笼统构建人物共同的接口。
  • 详细装修人物(Concrete Decrator):担任给构建方针贴上附加的职责。

2.3 装修形式的长处

装修形式的长处:

  • 装修形式与承继联系的目的都是要扩展方针的功用,可是装修形式能够供给比承继更多的灵敏性。
  • 能够经过一种动态的办法来扩展一个方针的功用,经过装备文件能够在运行时选择不同的装修器,从而完成不同的行为。
  • 经过运用不同的详细装修类以及这些装修类的排列组合,能够创造出许多不同行为的组合。能够运用多个详细装修类来装修同一方针,得到功用更为强壮的方针。
  • 详细构件类与详细装修类能够独立改动,用户能够根据需求增加新的详细构件类和详细装修类,在运用时再对其进行组合,原有代码无须改动,契合“开闭准则”

装修形式的缺点:

  • 运用装修形式进行体系规划时将发生许多小方针,这些方针的区别在于它们之间相互连接的办法有所不同,而不是它们的类或许特点值有所不同,一起还将发生许多详细装修类。这些装修类和小方针的发生将增加体系的复杂度,加大学习与理解的难度。
  • 这种比承继愈加灵敏机动的特性,也一起意味着装修形式比承继愈加易于出错,排错也很困难,关于屡次装修的方针,调试时寻找错误可能需求逐级排查,较为烦琐。

2.4装修形式的适用环境

  • 在不影响其他方针的情况下,以动态、通明的办法给单个方针增加职责。
  • 需求动态地给一个方针增加功用,这些功用也能够动态地被撤销。
  • 当不能选用承继的办法对体系进行扩大或许选用承继不利于体系扩展和维护时。不能选用承继的情况主要有两类:第一类是体系中存在很多独立的扩展,为支撑每一种组合将发生很多的子类,使得子类数目呈爆炸性增长;第二类是因为类界说不能承继(如final类).

2.5 上demo

JYM 设计模式系列- 责任链模式,装饰模式,让你的代码更优雅!!!

Troll:巨魔接口

public interface Troll {
  void attack(); //进犯
  int getAttackPower(); // 获取进犯力
  void fleeBattle(); //逃离战役
}

棒子巨魔完成巨魔接口:

@Slf4j
@RequiredArgsConstructor
public class ClubbedTroll implements Troll {
  private final Troll decorated;
  @Override
  public void attack() {
    decorated.attack();
    LOGGER.info("The troll swings at you with a club!");
  }
  @Override
  public int getAttackPower() {
    return decorated.getAttackPower() + 10;
  }
  @Override
  public void fleeBattle() {
    decorated.fleeBattle();
  }
}

一般的巨魔:

@Slf4j
public class SimpleTroll implements Troll {
  @Override
  public void attack() {
    LOGGER.info("The troll tries to grab you!");
  }
  @Override
  public int getAttackPower() {
    return 10;
  }
  @Override
  public void fleeBattle() {
    LOGGER.info("The troll shrieks in horror and runs away!");
  }
}

程序进口:

@Slf4j
public class App {
  /**
   * Program entry point.
   *
   * @param args command line args
   */
  public static void main(String[] args) {
    // simple troll
    LOGGER.info("A simple looking troll approaches.");
    var troll = new SimpleTroll();
    troll.attack();
    troll.fleeBattle();
    LOGGER.info("Simple troll power: {}.\n", troll.getAttackPower());
    // 经过增加装修器改动简略巨魔的行为
    LOGGER.info("A troll with huge club surprises you.");
    var clubbedTroll = new ClubbedTroll(troll);
    clubbedTroll.attack();
    clubbedTroll.fleeBattle();
    LOGGER.info("Clubbed troll power: {}.\n", clubbedTroll.getAttackPower());
  }
}

在这个例子中,咱们展示了简略的 SimpleTroll 如何首要进犯然后逃离 战役。然后咱们用 ClubbedTroll装修 SimpleTroll 并再次执行进犯。能够看到装修后行为发生了怎样的改动。

装修器形式是子类化的更灵敏的代替计划。 Decorator 类完成与方针相同的接口,并运用组合来“装修”对方针的调用。运用装修器形式能够在运行时改动类的行为。