Contents
  1. 1. 命令模式
    1. 1.1. 支持回退功能的命令模式
  2. 2. 责任链模式
    1. 2.1. 业务场景
    2. 2.2. 实现
    3. 2.3. 实现代码
  3. 3. 观察者模式
    1. 3.1. 参与者
    2. 3.2. 观察者模式适用于:
    3. 3.3. Demo业务场景
    4. 3.4. 实现代码

命令模式

  1. 5个角色:
  • 客户端 Client,负责构建所有对象
  • 具体命令 ConcreteCommand(处理某一个行为),多种行为多个实例化对象,但是自己并不执行,调用Receiver去执行方法。也是模式的核心所在,既可以实现不同功能的解耦,又可以实现直接调用所不能提供的额外功能。
  • Commmand
  • 触发器(请求者) Invoker
  • 接收执行者 Receiver
  1. 原理:Client不直接调用Reciver,而是通过Invoker和ConcreteCommand作为中间媒介去调用Reciver,ConcreteCommand存在的意义是做一些方法增强的操作,比如记录、事务、回退等功能,Invoker的作用是组装需要的Commands,把无关的行为屏蔽掉。

  2. 过程:

  • 客户端 创建N个具体的命令且指定Receiver
  • 客户端 把创建好的命令对象装配成一个 Invoker
  • 客户端 调用Invoker里面的方法,间接的通过ConcreteCommand来操作Receiver执行命令
  1. 使用场景:比如要对行为进行”记录日志、操作全部撤销/最近一个操作回退、事务”等处理,可以实现二者之间的松耦合。

支持回退功能的命令模式

commond接口实现 excute(); un()功能。
不同的功能模块去实现这2个方法,但是每个模块额外添加一个数组或者栈去记录操作顺序,然后就可以提供顺序撤销的功能了。
http://www.cnblogs.com/JsonShare/p/7206513.html

  • Client

    public class Client {
    public static void main(String[] args) {
    //创建接收者
    Computer computer = new Computer();
    //创建具体命令并且指定接收者
    DirCommand dirCommand = new DirCommand(computer);
    FileCommand fileCommand = new FileCommand(computer);
    //创建请求者
    Invoker invoker = new Invoker(fileCommand,dirCommand);
    /***********创建目录及撤销**************/
    //创建目录
    invoker.createDir("C:\\Users\\502764158\\Desktop\\io\\aa");
    invoker.createDir("C:\\Users\\502764158\\Desktop\\io\\bb");
    invoker.createDir("C:\\Users\\502764158\\Desktop\\io\\cc");
    invoker.undoDir();
    invoker.undoDir();
    invoker.undoDir();
    invoker.undoDir();
    }
    }
  • Recevier(支持2个模块 文件和目录模块的创建和删除)

    public class Computer {
    public void createDir(String path){
    File dir = new File(path);
    if (dir.exists()) {
    System.out.println("创建目录 " + path + " 失败,目标目录已经存在");
    }else{
    //创建目录
    if (dir.mkdirs()) {
    System.out.println("创建目录 " + path + " 成功");
    } else {
    System.out.println("创建目录 " + path + " 失败");
    }
    }
    }
    public void deleteDir(String path){
    File dir = new File(path);
    if(dir.exists()) {
    if(dir.delete()){
    System.out.println("删除目录 " + path + " 成功");
    }else{
    System.out.println("删除目录 " + path + " 失败");
    }
    }else{
    System.out.println("删除目录 " + path + " 失败,目标目录不存在");
    }
    }
    public void createFile(String name){}
    public void deleteFile(String name){}
    }
  • Command

    public interface Command {
    void execute(String path);
    void undo();
    }
  • DirCommand

    public class DirCommand implements Command{
    private DirCommand(){};
    private Computer computer;
    DirCommand(Computer computer){
    this.computer=computer;
    }
    List<String> list=new ArrayList();
    @Override
    public void execute(String path) {
    computer.createDir(path);
    list.add(path);
    }
    @Override
    public void undo() {
    if(list.size()>0){
    String path=list.get(list.size()-1);
    computer.deleteDir(path);
    list.remove(list.size()-1);
    }else{
    System.out.println("没有需要撤销的操作!");
    }
    }
    }
  • FileCommand

    public class FileCommand implements Command{
    private FileCommand(){};
    private Computer computer;
    FileCommand(Computer computer){
    this.computer=computer;
    }
    List<String> list=new ArrayList();
    @Override
    public void execute(String path) {
    }
    @Override
    public void undo() {
    }
    }
  • Invoker

    public class Invoker {
    private FileCommand fileCommand;
    private DirCommand dirCommand;
    Invoker(FileCommand fileCommand,DirCommand dirCommand){
    this.fileCommand=fileCommand;
    this.dirCommand=dirCommand;
    }
    public void createDir(String path){
    dirCommand.execute(path);
    }
    public void undoDir(){
    dirCommand.undo();
    }
    public void createFile(String path){
    fileCommand.execute(path);
    }
    public void undoFile(){
    fileCommand.undo();
    }
    }

责任链模式

IF-ELSE的高级版本。为请求创建了一个接收者对象的单向链表,通常每个接收者都包含对下一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。从而对请求的发送者和接收者进行解耦。

业务场景

有一个银行的借款系统可以帮助用户借款,负责该系统的有职员,组长还有经理,他们的等级由低到高,并且他们能够允许借款的额度也是从低到高的,分别是:

  • 职员最高可以批准 5000 元的借款额度
  • 组长最高可以批准 20000 元的借款额度
  • 经理最高可以批准 100000 元的借款额度
  • 当有转账的请求过来时,先由等级低的员工处理,若无法处理,则将请求移交给上级处理。

    public void test(Request request) {
    int money = request.getRequestMoney();
    if(money <= 1000) {
    Clerk.response(request);
    } else if(money <= 5000) {
    Leader.response(request);
    } else if(money <= 10000) {
    Manager.response(request);
    }
    }
  • IF-ELSE代码臃肿: 实际应用中的判定条件通常不是这么简单地判断金额,也许需要复杂的操作,也许需要查询数据库等等,这就会产生许多额外的代码,如果判断条件再比较多的话,那么代码就会大量地堆积在同一个文件中。一坨判断看的眼花。

  • IF-ELSE耦合度高:如果我们想继续添加处理请求的类,那么就需要添加 else if 的判定条件;另外,这个条件判定的顺序也是写死的。如果想改变顺序,那么也只能修改这个条件语句。
    利用责任链模式,请求者不需要知道谁是真正的接收者,而且接收者A只需要知道他的下线,不需要知道所有的接收者。

实现

  • 关键代码:Handler 里面聚合它自己,在 HanleRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
  • 何时使用:在处理消息的时候以过滤很多道。
  • 缺点:
  1. 不能保证请求一定被接收。
  2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
  3. 可能不容易观察运行时的特征,有碍于除错。

实现代码

  1. 抽象一个处理模型

    public abstract class AbstractLogger {
    public static int INFO = 1;
    public static int DEBUG = 2;
    public static int ERROR = 3;
    protected int level;
    //责任链中的下一个元素
    protected AbstractLogger nextLogger;
    public void setNextLogger(AbstractLogger nextLogger){
    this.nextLogger = nextLogger;
    }
    public void logMessage(int level, String message){
    if(this.level <= level){
    write(message);
    }
    if(nextLogger !=null){
    nextLogger.logMessage(level, message);
    }
    }
    abstract protected void write(String message);
    }
  2. 创建不同的Node

    public class ErrorLogger extends AbstractLogger {
    public ErrorLogger(int level){
    this.level = level;
    }
    @Override
    protected void write(String message) {
    System.out.println("Error Console::Logger: " + message);
    }
    }
    public class FileLogger extends AbstractLogger {
    public FileLogger(int level){
    this.level = level;
    }
    @Override
    protected void write(String message) {
    System.out.println("File::Logger: " + message);
    }
    }
    public class ConsoleLogger extends AbstractLogger {
    public ConsoleLogger(int level){
    this.level = level;
    }
    @Override
    protected void write(String message) {
    System.out.println("Standard Console::Logger: " + message);
    }
    }
  3. 把link按照业务逻辑串起来

    public class LoggerChain {
    static AbstractLogger getChainOfLoggers(){
    AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
    AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
    AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    return errorLogger;
    }
    }
  4. 用户端调用

    public class Client {
    public static void main(String[] args) {
    AbstractLogger loggerChain = LoggerChain.getChainOfLoggers();
    loggerChain.logMessage(AbstractLogger.INFO,
    "This is an information.");
    loggerChain.logMessage(AbstractLogger.DEBUG,
    "This is an debug level information.");
    loggerChain.logMessage(AbstractLogger.ERROR,
    "This is an error information.");
    }
    }

观察者模式

https://zhuanlan.zhihu.com/p/25045567

参与者

这种互相抽象的模式,实现了高度的解耦和灵活。

  • 被观察者(Subject):知道它的通知对象,事件发生后会通知所有它知道的对象,提供添加删除观察者的接口。
  • 观察者(Observer):提供通知后的更新事件
  • 具体被观察者(ConcreteSubject):被观察者具体的实例,存储观察者感兴趣的状态。
  • 具体观察者(ConcreteObserver):观察者的具体实现。

观察者模式适用于:

  • 当一个对象在不知道对方具体是如何实现时需要通知其它对象(因为添加的观察者是抽象类,具体如何实现要看注入的具体观察者
  • 当一个对象改变需要通知不确定数的对象时

Demo业务场景

场景:你被要求开发一个简单的股票监控应用程序。初始要求是:

  • 股票有一个符号名称和当前价格。
  • 投资者可以监控它的当前价值股票。
  • 当股票价格变化时,所有监测的股票投资者都被告知变化。
    通过Stock和Investor同时抽象,可以实现一个股民可以观察多个股票,一个股票价格变动可以通知多个股民

实现代码

  • 把股票抽象起来

    public abstract class Stock {
    private Vector<Investor> investors = new Vector<Investor>();
    protected int price = 0;
    public void addInvestor(Investor i){
    this.investors.add(i);
    }
    public void delInvestor(Investor i){
    this.investors.remove(i);
    }
    protected void notifyInvestors(int price,String stockName){
    System.out.println("begin to notify the investors.");
    for(Investor i:investors){
    i.update(price,stockName);
    }
    };
    public abstract void setPrice(int price);
    }
  • 把观察者抽象起来

    public interface Investor {
    public void update(int state,String stockName);
    }
  • 实现某个具体的股票:信息发展

    public class XXFZStock extends Stock{
    public String name="300469";
    public void setPrice(int price){
    System.out.println("change price.");
    this.price = price;
    this.notifyInvestors(price,name);
    }
    }
  • 实现某个北京的股民

    public class BeijingInvestor implements Investor {
    private String name;
    public BeijingInvestor(String name){
    this.name = name;
    }
    public void update(int price,String stockName){
    System.out.println("Beijing Investor " + this.getName() + " know the "+stockName+" stock change to " + price);
    }
    public String getName(){
    return this.name;
    }
    }
  • 客户端操作模拟北京某股民顶上 300469后,股票价格发生波动

    public class Client {
    public static void main(String[] args){
    Stock stock = new XXFZStock();
    stock.addInvestor(new BeijingInvestor("Huangzs"));
    stock.setPrice(19);
    stock.setPrice(25);
    }
    }
Contents
  1. 1. 命令模式
    1. 1.1. 支持回退功能的命令模式
  2. 2. 责任链模式
    1. 2.1. 业务场景
    2. 2.2. 实现
    3. 2.3. 实现代码
  3. 3. 观察者模式
    1. 3.1. 参与者
    2. 3.2. 观察者模式适用于:
    3. 3.3. Demo业务场景
    4. 3.4. 实现代码