Java设计模式之java命令模式详解

编辑: admin 分类: java 发布时间: 2021-12-03 来源:互联网
目录
  • 命令模式的介绍
  • 角色
  • 订单案例
  • 命令模式的优点
  • 适用场景
  • 示例代码
  • 应用
    • 宏命令----执行一组命令
    • 示例代码
  • 总结
    • JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法
      • 总结

        命令模式的介绍

        在这里插入图片描述

        命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象

        每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

        角色

        • 客户端(Client)角色:创建一个具体命令(ConcreteCommand)对象并确定其接收者。
        • 命令(Command)角色:声明了一个给所有具体命令类的抽象接口。
        • 具体命令(ConcreteCommand)角色:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法。
        • 请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。
        • 接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

        订单案例

        在这里插入图片描述

        在这里插入图片描述

        在这里插入图片描述

        代码演示

        将客人点餐的请求封装为一个请求对象,即订单类

        //将客人点餐的请求封装为一个请求类
        //即订单类
        public class Order
        {
            //几号桌点餐
            private  Integer diningTable;
            //当前桌客人点的菜品
            private Map<String,Integer> FoodDic=new HashMap<>();
            public Integer getDiningTable() {
                return diningTable;
            }
            public void setDiningTable(Integer diningTable) {
                this.diningTable = diningTable;
            }
            public Map<String, Integer> getFoodDic() {
                return FoodDic;
            }
            public void setFoodDic(String foodName,Integer num)
            {
                FoodDic.put(foodName,num);
            }
        }
        

        抽象命令类

        //抽象命令类
        public abstract class Command
        {
            //执行命令的抽象方法
            public abstract void execute();
        }
        

        具体命令类—订单命令

        //具体订单命令
        public class OrderCommand extends Command {
            //持有接受者对象和订单对象
            private SeniorChef chef;
            private Order order;
            //通过构造函数为属性赋值
            OrderCommand(SeniorChef seniorChef,Order order)
            {
                this.chef=seniorChef;
                this.order=order;
            }
            //通过调用接受者对象的方法,来执行命令的具体逻辑行为
            @Override
            public void execute()
            {
                System.out.println(order.getDiningTable()+"号桌的订单");
                //遍历集合: key-->foodName value--->食物点了几份
                order.getFoodDic().forEach((key,value)->{
                    chef.makeFood(key,value);
                });
            }
        }
        

        接收者

        //厨师类
        public class SeniorChef
        {
            //制作食物
            public void makeFood(String name,Integer num)
            {
                System.out.println("制作"+name+"  "+num+"份");
            }
        }
        

        请求者

        //服务员类----发送请求(命令)者
        public class Waitor
        {
              //命令可能有多个
            List<Command> commadns= Lists.newArrayList();
            //将命令放入到集合中
            public void setCmd(Command cmd)
            {
                commadns.add(cmd);
            }
            //发起命令功能
            public void OrderUp()
            {
                System.out.println("订单来了.....");
                //遍历List集合
                commadns.forEach(cmd->{
                    if(cmd!=null)
                        //命令有效就执行
                        cmd.execute();
                });
            }
        }
        

        客户端

                //创建订单对象---请求被包装成一个类
                Order order=new Order();
                order.setDiningTable(1);
                order.setFoodDic("大鸡腿",2);
                //创建厨师对象---接收者
                SeniorChef chef=new SeniorChef();
                //创建命令类--组合接受者和具体请求
                Command command=new OrderCommand(chef,order);
                //创建服务员---调用者
                Waitor waitor=new Waitor();
                //将命令组合进去
                waitor.setCmd(command);
                //执行命令
                waitor.OrderUp();
        

        在这里插入图片描述

        命令模式的优点

        命令允许请求的一方和接收请求的一方能够独立演化,从而具有以下的优点:

        (1)命令模式使新的命令很容易地被加入到系统里。

        (2)允许接收请求的一方决定是否要否决请求。

        (3)能较容易地设计一个命令队列。

        (4)可以容易地实现对请求的撤销和恢复====>可以结合备忘录模式实现

        (5)在需要的情况下,可以较容易地将命令记入日志。

        下面以一个示意性的系统,说明命令模式的结构。

        在这里插入图片描述

        命令模式的初衷:对命令请求者(Invoker)和命令实现者(Receiver)的解耦,方便对命令进行各种控制。

        适用场景

        • 命令的发送者和命令执行者有不同的生命周期。命令发送了并不是立即执行。
        • 命令需要进行各种管理逻辑。
        • 需要支持撤消\重做操作(这种状况的代码大家可以上网搜索下,有很多,这里不进行详细解读)。

        示例代码

        接收者角色类

        public class Receiver {
            /**
             * 真正执行命令相应的操作
             */
            public void action(){
                System.out.println("执行操作");
            }
        }
        

        抽象命令角色类

        public interface Command {
            /**
             * 执行方法
             */
            void execute();
        }
        

        具体命令角色类

        public class ConcreteCommand implements Command {
            //持有相应的接收者对象
            private Receiver receiver = null;
            /**
             * 构造方法
             */
            public ConcreteCommand(Receiver receiver){
                this.receiver = receiver;
            }
            @Override
            public void execute() {
                //通常会转调接收者对象的相应方法,让接收者来真正执行功能
                receiver.action();
            }
        }
        

        请求者角色类

        public class Invoker {
            /**
             * 持有命令对象
             */
            private Command command = null;
            /**
             * 构造方法
             */
            public Invoker(Command command){
                this.command = command;
            }
            /**
             * 行动方法
             */
            public void action(){
                command.execute();
            }
        }
        

        客户端角色类

        public class Client {
            public static void main(String[] args) {
                //创建接收者
                Receiver receiver = new Receiver();
                //创建命令对象,设定它的接收者
                Command command = new ConcreteCommand(receiver);
                //创建请求者,把命令对象设置进去
                Invoker invoker = new Invoker(command);
                //执行方法
                invoker.action();
            }
        }
        

        通过一个command命令类,实现接收者与执行者的解耦操作

        应用

        宏命令----执行一组命令

        所谓宏命令简单点说就是包含多个命令的命令,是一个命令的组合。

        示例代码

        系统需要一个代表宏命令的接口,以定义出具体宏命令所需要的接口。

        public interface MacroCommand extends Command {
            /**
             * 宏命令聚集的管理方法
             * 可以添加一个成员命令
             */
            public void add(Command cmd);
            /**
             * 宏命令聚集的管理方法
             * 可以删除一个成员命令
             */
            public void remove(Command cmd);
        }
        

        具体的宏命令MacroAudioCommand类负责把个别的命令合成宏命令。

        public class MacroAudioCommand implements MacroCommand {
            private List<Command> commandList = new ArrayList<Command>();
            /**
             * 宏命令聚集管理方法
             */
            @Override
            public void add(Command cmd) {
                commandList.add(cmd);
            }
            /**
             * 宏命令聚集管理方法
             */
            @Override
            public void remove(Command cmd) {
                commandList.remove(cmd);
            }
            /**
             * 执行方法
             */
            @Override
            public void execute() {
                for(Command cmd : commandList){
                    cmd.execute();
                }
            }
        }
        

        客户端类

        public class Julia {
            public static void main(String[]args){
                //创建接收者对象
                AudioPlayer audioPlayer = new AudioPlayer();
                //创建命令对象
                Command playCommand = new PlayCommand(audioPlayer);
                Command rewindCommand = new RewindCommand(audioPlayer);
                Command stopCommand = new StopCommand(audioPlayer);
                MacroCommand marco = new MacroAudioCommand();
                marco.add(playCommand);
                marco.add(rewindCommand);
                marco.add(stopCommand);
                marco.execute();
            }
        }
        

        总结

        更松散的耦合

        命令模式使得发起命令的对象——客户端,和具体实现命令的对象——接收者对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。

        更动态的控制

        命令模式把请求封装起来,可以动态地对它进行参数化、队列化和日志化等操作,从而使得系统更灵活。

        很自然的复合命令

        命令模式中的命令对象能够很容易地组合成复合命令,也就是宏命令,从而使系统操作更简单,功能更强大。

        更好的扩展性

        由于发起命令的对象和具体的实现完全解耦,因此扩展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,然后就可以使用这个命令对象,已有的实现完全不用变化。

        JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法

        //命令接口(抽象命令角色)
        public interface Runnable {
            public abstract void run();
        }
        ​
        //调用者
        public class Thread implements Runnable {
            private Runnable target;
            public synchronized void start() {
                if (threadStatus != 0)
                    throw new IllegalThreadStateException();
        ​
                group.add(this);
        ​
                boolean started = false;
                try {
                    start0();
                    started = true;
                } finally {
                    try {
                        if (!started) {
                            group.threadStartFailed(this);
                        }
                    } catch (Throwable ignore) {
                    }
                }
            }
            private native void start0();
        }
        

        会调用一个native方法start0(),调用系统方法,开启一个线程。

        而接收者是对程序员开放的,可以自己定义接收者。

        /**
         * jdk Runnable 命令模式
         *      TurnOffThread : 属于具体
         */
        public class TurnOffThread implements Runnable{
             private Receiver receiver;
             public TurnOffThread(Receiver receiver) {
                this.receiver = receiver;
             }
             public  void run() {
                receiver.turnOFF();
             }
        
        **
         * 测试类
         */
        public class Demo {
             public static void main(String[] args) {
                 Receiver receiver = new Receiver();
                 TurnOffThread turnOffThread = new TurnOffThread(receiver);
                 Thread thread = new Thread(turnOffThread);
                 thread.start();
             }
        }
        

        总结

        本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注自由互联的更多内容!

        【转自:荷兰服务器