zoukankan      html  css  js  c++  java
  • 命令模式

      命令模式定义:在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)。

      在网上找了个命令模式的标准类图

      命令模式中有五种角色,分别是:

      1、抽象命令(Command):定义命令的接口,声明执行的方法

      2、具体命令(ConcreteCommand):具体命令,实现要执行的方法,它通常是“虚”的实现;通常会有接收者,并调用接收者的功能来完成命令要执行的操作。

      3、接收者(Receiver):真正执行命令的对象。任何类都可能成为一个接收者,只要能实现命令要求实现的相应功能。

      4、调用者(Invoker):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

      5、客户端(Client):命令由客户端来创建,并设置命令的接收者。

      我们以顾客到餐馆吃饭为例,顾客先要点单,然后交与服务员,服务员拿着单子去找后厨按要求做菜,这便是命令模式的体现,实现了顾客和厨师的解耦,在这个过程中顾客便是我们的client,单子便是具体的command,服务员是invoker,厨师就是具体的实现者receiver。下面是demo

      首先是makefood接口,相当于抽象命令

    package io.powerx.command;
    
    public interface MakeFood {
    
        void execute();
    }

      三种实现类,制作不同的食物,在实现类中持有我们的cook,调用cook的方法完成制作

    package io.powerx.command;
    
    public class MakeBread implements MakeFood {
    
        private Cook cook;
        
        public MakeBread(Cook cook) {
            super();
            this.cook = cook;
        }
    
        @Override
        public void execute() {
            
            cook.makeBread();
        }
    
    }
    package io.powerx.command;
    
    public class MakeRoast implements MakeFood {
    
        private Cook cook;
        
        public MakeRoast(Cook cook) {
            super();
            this.cook = cook;
        }
    
        @Override
        public void execute() {
            
            cook.makeRoast();
        }
    
    }
    package io.powerx.command;
    
    public class MakeChicken implements MakeFood {
    
        private Cook cook;
        
        public MakeChicken(Cook cook) {
            super();
            this.cook = cook;
        }
    
        @Override
        public void execute() {
            
            cook.makeChicken();
        }
    
    }

      厨师类

      

    package io.powerx.command;
    
    public class Cook {
    
        private String name;
        
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Cook(String name) {
            super();
            this.name = name;
        }
    
        public void makeBread() {
            System.out.println(name +"  make  bread"); 
        }
        
        public void makeRoast() {
            System.out.println(name + " make roast"); 
        }
        
        public void makeChicken () {
            System.out.println(name + " make chicken");
        }
    }

      服务员类,它持有一个Makefood的list,用来存储顾客的点单信息

    package io.powerx.command;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Waiter {
        
        private String name;
        
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<MakeFood> getList() {
            return list;
        }
    
        public void setList(List<MakeFood> list) {
            this.list = list;
        }
    
        public Waiter(String name) {
            super();
            this.name = name;
            this.list = new ArrayList<>();
        }
    
        private List<MakeFood> list;
        
        public void receive(MakeFood makeFood) {
            list.add(makeFood);
            
        }
        
        public void assign() {
            System.out.println("waiter " + name + "分配制作任务");
            for (int i=0;i<list.size();i++) {
                list.get(i).execute();
            }
        }
    }

      顾客类

    package io.powerx.command;
    
    public class Customer {
    
        private String name;
        public Customer(String name) {
            super();
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void orderBread(Waiter w,Cook c) {
            System.out.println(name+"order bread");
            w.receive(new MakeBread(c));
        }
        public void orderRoast(Waiter w,Cook c) {
            System.out.println(name+"order roast");
            w.receive(new MakeRoast(c));
        }
        public void orderChicken(Waiter w,Cook c) {
            System.out.println(name+"order chicken");
            w.receive(new MakeChicken(c));
        }
    }

      执行测试代码,结果如下:

        以上便是命令模式的标准实现,然而并没有达到顾客与厨师的解耦,我们的customer仍依赖于cook类,这tm就尴尬了,还不如直接在customer类中order*方法直接调cook的对应方法呢。只是学习设计模式切莫死搬硬套,我们只需要在waiter类中维护一个cook的list,由waiter决定哪个厨师来处理任务即可,这样我们的customer类就彻底与cook类解耦。

      修改waiter类如下

    package io.powerx.command;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class Waiter2 {
        
        private String name;
        
        private int currentIndex ;
        
        private List<Cook> cooklist;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<MakeFood> getList() {
            return list;
        }
    
        public void setList(List<MakeFood> list) {
            this.list = list;
        }
    
        
        public Waiter2(String name, Cook ...cooks) {
            super();
            this.name = name;
            this.cooklist = Arrays.asList(cooks);
            this.list = new ArrayList<>();
        }
        private List<MakeFood> list;
        
        public void receive(MakeFood makeFood) {
            list.add(makeFood);
            
        }
        
        public void assign() {
            System.out.println("waiter " + name + "分配制作任务");
            for (int i=0;i<list.size();i++) {
                list.get(i).execute();
            }
        }
        
        public Cook chooseCook() {
            Cook cook =  cooklist.get(currentIndex % cooklist.size()) ;
            currentIndex++;
            return cook;
        }
    
        public int getCurrentIndex() {
            return currentIndex;
        }
    
        public void setCurrentIndex(int currentIndex) {
            this.currentIndex = currentIndex;
        }
    
        public List<Cook> getCooklist() {
            return cooklist;
        }
    
        public void setCooklist(List<Cook> cooklist) {
            this.cooklist = cooklist;
        }
        
    }

      同时顾客类的调用方式也发生了变化

    package io.powerx.command;
    
    public class Customer2 {
    
        private String name;
        public Customer2(String name) {
            super();
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void orderBread(Waiter2 w) {
            System.out.println(name+"order bread");
            w.receive(new MakeBread(w.chooseCook()));
        }
        public void orderRoast(Waiter2 w) {
            System.out.println(name+"order roast");
            w.receive(new MakeRoast(w.chooseCook()));
        }
        public void orderChicken(Waiter2 w) {
            System.out.println(name+"order chicken");
            w.receive(new MakeChicken(w.chooseCook()));
        }
    }

      执行测试代码结果如下:

      改造后的类图如下:

      最后讲一下命令模式的适用场景,如果有以下需求,可以考虑使用命令模式:

      1、希望将行为请求者和行为实现者解耦,不直接打交道。

      2、希望可以控制执行的命令列表,方便记录,撤销/重做以及事务等功能。

      3、期待可以将请求排队,有序执行。

      4、希望可以将请求组合使用。

  • 相关阅读:
    Charles抓包工具的使用
    C++中引用(&)的用法和应用实例
    机器学习-斯坦福:学习笔记7-最优间隔分类器问题
    机器学习-斯坦福:学习笔记6-朴素贝叶斯
    机器学习-斯坦福:学习笔记5-生成学习算法
    机器学习-斯坦福:学习笔记4-牛顿方法
    机器学习-斯坦福:学习笔记3-欠拟合与过拟合概念
    机器学习-斯坦福:学习笔记2-监督学习应用与梯度下降
    机器学习-斯坦福:学习笔记1-机器学习的动机与应用
    相似性计算方法
  • 原文地址:https://www.cnblogs.com/hhhshct/p/10255330.html
Copyright © 2011-2022 走看看