【笨鸟先飞】Java重新学习日记19--设计模式之命令模式

设计模式是面向对象设计的精华,而面向对象终归于继承、封装和多态。我本次学习设计模式重在体会面向对象设计的思维方式,同时知晓该设计模式的应用场景,当后来遇到相似场景,可以直接借鉴该设计模式。

 

思考一个场景,如上次学习的策略模式一样,一个对象要调用另一个的方法而这个方法是相似的,我们用有很多算法用来替代,则采用一个抽象内,用子类来实现算法。

 

命令模式借鉴了策略模式的经验,就像单例模式借鉴了工厂模式一样。命令模式是以策略模式为基础,重点实现了多个客户端的多种调用的解耦。

 

先简单回忆一下策略模式。

策略模式有一个抽象类传入给客户端A,而实际使用时,各类算法以抽象类的子类传入。则使用算法的客户端A,将创建正确的算法子类对象,以抽象类为参数传入,最后调用其中的关键方法。

 

接来下看一下命令模式的场景。

有几个完全无关的类BCD,但在大类A中,BCD在相似的场景下会被经常调用。

 

先举几个应用场景的案例:

 

1.《设计模式》书中案例,BCD分别是宫保鸡丁,紫菜蛋花汤,麻辣小龙虾。而A是顾客点的订单。在实际操作中,一个顾客的点单有多个菜品组成,对于订单对象的生成采用工厂模式。但在这个场景下,我们发现很难将BCD用同一个父类连接到一起,假设用一个菜,作为BCD的父类,那么里面能提供什么公共的方法?---- 方法excute()

 

2. BCD分别是打开应用,调节音量,开关机。而A是手机,这BCD是手机的三个功能,我们也发现很难用一个父类连接到一起。------ 实际操作由具体的receive来实现

 

 

3. BCD分别是手刹,转向灯,方向盘。而A是汽车。和上一个例子相比更加困难了。驾校学习将车启动有很多步奏,都在启动的时候做,其中包括松手刹,打左转向灯和往左打方向盘。这是一套行为,但是其中步奏相互没有关联,但是每次开车都要用,考虑一起完成--- 宏命令

 

上面的应用场景都算是比较常见的,我们本想使用策略模式来完成,但是这里存在一个关键性难题:公共父类的实现。

 

所以策略模式和命令模式最大的区别,也是命令模式的核心创新点。用公共类来传递行为而不是东西本身。

命令模式传递的是命令是行为。公共父类是行为的集合,而具体的实现类还是分开的。

以场景3为例,公共对象是一个抽象的行为,而实际行为是,拉手刹,松手刹,左转方向盘,右转方向盘,打开右转向灯,打开左转向灯,关闭转向灯。

手刹、方向盘、转向灯依然是分别独立的类,我们将操作他们的行为统一到了一起。

 

 

下面看看怎么实现命令模式。

 

根据定义,一个完整的命令模式包括 client involkercommandconcreateCommandreceive

下面来理一下每个的含义。

其中command就是情况1里面提到的公共父类,其方法只有一个就是excute(),这是对行为,也就是对“命令”这个词语的封装。Command就是一个抽象类,里面只有一个方法。

concreateCommand是继承自command里面会写具体的excute(),也就是需要BCD做什么。这个具体实现会创建较多的类,对于期望对象的每种操作,我们都会写成一个类。这个类会调用操作对象的方法,具体写在excute()中。在这个类的构造器中,传入操作对象,而后在excute()中调用该对象的方法。

 

Receive则是真正的对象BCD,他们在concreateCommand中被真正调用。

 

Involker里面包含两个方法,setcomand()和excute()这是一个接口性质的类,用于解耦,一个setcomand用于放入comand,可以放入一个,也可以放入多个command用集合存储。而execute则是调用commandexecute从而调用具体对象的方法。

  

  class Invoker  

    {  

        private Command command;  

 

        public void SetCommand(Command command)  

        {  

            this.command = command;  

        }  

   

        public void ExecuteCommand()  

        {  

            command.Execute();  

        }  

 

      }  

 

Client是真正享受命令模式福利的客户端。

 

使用顺序是:

创建BCD对象bcd

创建concreateCommand对象,构造器参数会传入bcd

创建involker对象,将concreateCommand对象, setinvolker中。

 

使用involker慢慢execute

 

当完成上面的创建工作后,involkerexecute就变得非常轻松了。

我们可以轻易的使用involker来进行相应bcdexecute行为。

 

这里有几大特征会产生一定的优势:

1client需要创建recerive对象,concreateCommand以及使用involker调用concreateCommandClient需要知道每个concreateCommand的具体名字,但是不需要知道concreateCommandexcute的具体内容。

反之,需要增加新的excute,对于client的修改就特别少。而且每次修改某个concreateCommand对其他的concreateCommand也没有影响。

这就是典型的解耦优势。

 

2.调用者多了之后,也就是client多了之后,反复调用效率会提高很多。

 

3.involkerexcute的时序优势,因为receiveexcute分开,同时involker在负责统一调用。则在调用多个excute的时候,同时调用或者一个完成在调用一个。 还可以采用列队、日志等消息传递方式来

 

4.involkersetcommand的方法中,我们可以讲set过的方法都存到集合里,然后在excute的时候,将集合中的command依次完成,这样就像开车,可以把开车的所有步骤都放到这个集合中,一次性完成开车的行为,这种操作叫做宏命令。

 

总的来说,命令模式在解耦方面有巨大的优势,特别是针对行为的解耦,当需要用策略模式,但策略模式不好用的时候,就尝试命令模式吧。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值