深入剖析Ruby设计模式编程中对命令模式的相关使用

命令模式是对象行为型使用率比较高的设计模式,别名:Action(动作),Transaction(事务)

意图: 将一个请求封装为一个对象,从而使你可对不同的请求进行参数化;对请求排队或记录请求日志,以及支持可取消的操作
这里所谓的“不同的请求”也既意味着请求可能发生的变化,是一个可能扩展的功能点。

动机: 方便扩展

结构:

协作说明:
   参与角色:
    Command 声明一个接口以用来实现某个操作。
    ConcreteCommand 将动作与Reciver对外绑定,通过调用Reciver对象的相应方法来实现Command的方法。
    Client 创建ConcreteCommand对象,并设置其Reciver对象。
  Invoker 要求该Command实现请求。
  Reciver 知道如何实现具体的请求的类。
  客户端创建了一个具体的Command对象并指定了其接收者。
  调用者对象存储了此具体的Command对象。
  调用者对象通过执行Command对象的Execute方法来实现当前请求。
  如果命令是可以撤销时,具体对象在调用执行方法前将存储相应的状态以用来命令此请求。
  具体的Command对象调用其接收者的方法从而来实现相应请求。

适用性:
类似于 MenuItem , 抽象出待执行的动作以参数化某对象
在不同的时刻指定,排列,执行请求
支持撤消
支持修改日志
在构建在原语操作上的高层操作构造一个系统(其实就是事务)

动态性方面: 像ruby中 block 就是命令模式

效果:
命令模式将调用者对象与接收对象解耦(调用与实现解耦)。调用者实现功能时只需调用Command接口的Execute方法。
具体的Commands对象是第一层对象,它们可以像其他对象一样被扩展或操作。
你可以将多个Commands对象聚合成一个组合命令。组合命令也是组合对象模式的一个实例,将命令排队也是其的一种特殊情况。
你可以很容易的添加新的命令,因为你并不需要修改现有的代码。这也符合了开闭原则,对修改关闭,对扩展开放。

实现时应考虑命令对象应达到何种智能程序和支持撤消和重做这两个问题.

误用:
不要着迷 到底哪个简单?
命令模式不是说“做这个” 说“ 记住这个如何做”,稍后再说”按照我刚才要你记住的方法做这个”
小心撤销,许多操作是破坏性的,如删除文件操作

类图:

class Button

 attr_accessor :name, :command

 def initialize name, command
  @name = name
  @command = command
 end

 def do_something
  @command.execute
 end

end

class Command

 def execute
  "root execute"
 end

end

class PaintCommand < Command

 def execute
  "draw something"
 end

end

class VocalCommand < Command

 def execute
  "talk something"
 end

end

paintCommand = PaintCommand.new
vocalCommand = VocalCommand.new
button = Button.new("button", paintCommand)
p button.do_something
button.command = vocalCommand
p button.do_something

定义了主体类Button,Button聚合一个命令对象Command,声明Command,PaintCommand,VocalCommand三个具有继承的命令类,在系统当中可能存在有多个Button,每个Button所要完成的事情是不一样的,即这个部分是变化的的,也就是方法do_something中的代码也是不确定的,将这部分的代码分离到单独的对象中进行管理,而这个对象就被称为命令对象,命令对象只负责需要完成的任务或者是指令,主体对象可以根据自己的需要在任何时间去调用需要的命令进行执行。在调用处的代码中也非常清晰的发现要切换当前Button的命令实现非常方便,也非常灵活,只需要简单的却调用set方法就可以完成。如果采用Button继承的关系,第一主体对象会造成类爆炸,第二在切换命令实现的时候对比这种方式就会比较困难。
 
使用ruby proc来完成命令模式 :

class Button

 attr_accessor :name

 def initialize name, &command
  @name = name
 end

 def do_something &command
  command.call
 end

end

paint_command = lambda do
 p "paint something"
end

vocal_command = lambda do
  p "talk something"
end

button = Button.new ("name")
button.do_something &vocal_command
button.do_something &paint_command

可以看到使用block来代替命令类更加简单,易懂,在实际项目环境中使用proc和命令可以情况而定,如果命令对象非常复杂,需要有自己的状态和方法,就选用命令类来完成,如果只是简单的处理一些小事情,便可以采用proc
 
如果需要执行的命令过多,可以定义命令队列,也就是一个命令里面管理多个命令, 当调用的时候挨个调用每个命令进行执行,从这一点来非常像组合模式
 
在某中意义上来说观察者模式和命令模式有一些相像,都是聚合一些具有共同特征的对象到自己类,然后根据情况来进行调用。但是2个模式有一个明显的区别,就是用途。观察者模式用于被观察者将变化通知到各个不同的观察者身上,而命令模式并不关心是否是通知到其他命令,命令对象只负责执行自己的任务或者是指令,并且命令模式可以记住前一次的操作,所以一般来说很多文本编辑器的撤销/重做都会用到命令模式。

时间: 2016-04-05

设计模式中的观察者模式在Ruby编程中的运用实例解析

观察者模式(有时又被称为发布/订阅模式)是软件设计模式的一种. 在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知. 这通常透过呼叫各观察者所提供的方法来实现. 实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能 体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来, 从根本上违反面向对象的设计的原则.无论是观察者"观察"观察对象, 还是被观察者将自己的改变"通知"观察者,都不应该直接调用.

Ruby设计模式编程中对外观模式的应用实例分析

何为外观模式? 外观模式为子系统中一组不同的接口提供统一的接口.外观定义了上层接口,通过降低复杂度和隐藏子系统间的通信以及依存关系,让子系统更加易于使用. 比方说子系统中有一组不同的类,其中一些彼此依赖.这让客户端难以使用子系统中的类,因为客户端需要知道每一个类.外观起到整个子系统的入口.有些客户端只需要子系统的某些基本行为,而对子系统的类不做太多定制,外观为这样的客户端提供简化的接口.只有需要从某些子系统的类定制更多行为的客户端,才会关注外观背后的细节. 外观模式:为系统中的一组接口提供一个统

解析proxy代理模式在Ruby设计模式开发中的运用

代理模式 Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上.在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层.如下图: 比如说C和A不在一个服务器上,A要频繁的调用C,我们可以在A上做一个代理类Proxy,把访问C的工作交给Proxy,这样对于A来说,就好像在直接访问C的对

设计模式中的模板方法模式在Ruby中的应用实例两则

实例一 今天你还是像往常一样来上班,一如既往地开始了你的编程工作. 项目经理告诉你,今天想在服务器端增加一个新功能,希望写一个方法,能对Book对象进行处理,将Book对象的所有字段以XML格式进行包装,这样以后可以方便与客户端进行交互.并且在包装开始前和结束后要打印日志,这样方便调试和问题定位. 没问题!你觉得这个功能简直是小菜一碟,非常自信地开始写起代码. Book对象代码如下: class Book attr_accessor :book_name, :pages, :price, :au

Ruby设计模式编程中使用Builder建造者模式的实例

先来复习一下设计模式的基本概念: 定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要重新定一个建造者就可以了. 实用范围 1.当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 2.当构造过程必须允许被构造的对象有不同表示时. 角色 在这样的设计模式中,有以下几个角色: 1.builder:为创建一个产品对象的各个部件指定抽象接口. 2.ConcreteBuilder:实现B

实例解析Ruby设计模式编程中Strategy策略模式的使用

今天你的leader兴致冲冲地找到你,希望你可以帮他一个小忙,他现在急着要去开会.要帮什么忙呢?你很好奇. 他对你说,当前你们项目的数据库中有一张用户信息表,里面存放了很用户的数据,现在需要完成一个选择性查询用户信息的功能.他说会传递给你一个包含许多用户名的数组,你需要根据这些用户名把他们相应的数据都给查出来. 这个功能很简单的嘛,你爽快地答应了.由于你们项目使用的是MySQL数据库,你很快地写出了如下代码: require 'mysql' class QueryUtil def find_us

详解组合模式的结构及其在Ruby设计模式编程中的运用

定义:也叫合成模式,或者部分-整体模式,主要是用来描述部分与整体的关系,定义,将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 类图: 角色说明: Componnent抽象构件角色:定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性. Leaf叶子构件:叶子对象,其下再也没有其他的分支,也就是遍历的最小单位. Composite树枝构件:树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构. 实例: 听说你们公司最近新

Ruby中使用设计模式中的简单工厂模式和工厂方法模式

之前有看过<ruby设计模式>,不过渐渐的都忘记了.现在买了一个大话设计模式,看起来不是那么枯燥,顺便将代码用ruby实现了一下. 简单工厂模式: # -*- encoding: utf-8 -*- #运算类 class Operation attr_accessor :number_a,:number_b def initialize(number_a = nil, number_b = nil) @number_a = number_a @number_b = number_b end d

Ruby设计模式编程之适配器模式实战攻略

适配器模式 适配器模式可以用于对不同的接口进行包装以及提供统一的接口,或者是让某一个对象看起来像是另一个类型的对象.在静态类型的编程语言里,我们经常使用它去满足类型系统的特点,但是在类似Ruby这样的弱类型编程语言里,我们并不需要这么做.尽管如此,它对于我们来说还是有很多意义的. 当使用第三方类或者库的时候,我们经常从这个例子开始(start out fine): def find_nearest_restaurant(locator) locator.nearest(:restaurant,

实例解析Ruby设计模式开发中对观察者模式的实现

一般来说,观察者模式的定义应该是这样的:building a clean interface between the source of news that some object has changed and the consumers of that news. 观察者模式在消息的生产者和消费者之间建立了clean interface,这样就使得消息的生产者和消费者之间的耦合是抽象的.被观察者可以不认识任何一个的观察者,它只知道他们都实现了一个共同的接口.由于观察者和被观察者没有紧密的耦合

实例讲解Ruby使用设计模式中的装饰器模式的方法

概述        若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一  个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类-这建立在额外的代码上.       通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是静态的,用户不能控制增加行为的方式和时机.如果  你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,

Ruby使用设计模式中的代理模式与装饰模式的代码实例

代理模式 需求: 小明让小李替他追小丽(送洋娃娃,送花,送巧克力) 没有代理的代码: # -*- encoding: utf-8 -*- #追求者类 class Pursuit attr_accessor :mm def initialize(mm) @mm = mm end def give_dolls puts "#{mm.name} 送你洋娃娃" end def give_flowers puts "#{mm.name} 送你鲜花" end def give_

详解Ruby设计模式编程中对单例模式的运用

简介       单例模式是设计模式中最简单的形式之一.这一模式的目的是使得类的一个对象成为系统中的唯一实例.要实现这一点,可以从客户端对其进行实例化开始.因此需要用一种只允许生成对象类的唯一实例的机制,"阻止"所有想要生成对象的访问.使用工厂方法来限制实例化过程.这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义. 要点       显然单例模式的要点有三个:一是某个类只能有一个实例:二是它必须自行创建这个实例:三是它必须自行向整个系统提供这个实例.    

详解Java设计模式编程中的策略模式

定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 类图: 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过的行为类模式中,有一种模式也是关注对算法的封装--模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装类Context,它与模版方法模式的区别在于:在模版方法模式中,调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是封装到了封装类Context中

详解Java设计模式编程中的访问者模式

定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 类型:行为类模式 类图: 例子: 例如,思考一下添加不同类型商品的购物车,当点击结算的时候,它计算出所有不同商品需付的费用.现在,计算逻辑即为计算这些不同类型商品的价格.或者说通过访问者模式我们把此逻辑转移到了另外一个类上面.让我们实现这个访问者模式的例子. 为了实现访问者模式,最先需要做的是创建能够被添加到购物车中代表不同类型商品(itemElement)的类. ItemElement

详解Java设计模式编程中的Flyweight享元模式的开发结构

享元(Flyweight)模式:通过共享技术以便有效的支持大量细粒度的对象. 享元模式在阎宏的<java与模式>中分为单纯享元模式和复合享元模式,复合模式的复合享元是不可以共享的,享元对象能做到共享的关键是区分内蕴态(Internal State)和外蕴态( External State).这两个"蕴态"翻译的太难懂,我不是说翻译的不好,可能是我理解能力差,还是<Design Pattern Elements of Reusable Object-Oriented S

详解Java设计模式编程中的依赖倒置原则

定义: 高层模块不应该依赖低层模块,二者都应该依赖其抽象:抽象不应该依赖细节:细节应该依赖抽象. 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成.这种场景下,类A一般是高层模块,负责复杂的业务逻辑:类B和类C是低层模块,负责基本的原子操作:假如修改类A,会给程序带来不必要的风险. 解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率.          依赖倒置原则基于这样一个事实:

详解C#设计模式编程中的模板方法模式使用

一.引言 提到模板,大家肯定不免想到生活中的"简历模板"."论文模板"."Word中模版文件"等,在现实生活中,模板的概念就是--有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简历模板,下载下来的简历模板的格式都是相同的,然而我们下载下来简历模板之后我们可以根据自己的情况填充不同的内容要完成属于自己的简历.在设计模式中,模板方法模式中模板和生活中模板概念非常类似,下面让我们就详细介绍模板方法的定义,大家可以根据生活中模板的概

详解Java设计模式编程中命令模式的项目结构实现

正论: 命令模式把一个请求或者操作封装到一个对象中.命令模式运行系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 通俗: 其实很好理解.命令模式,关心的就是命令(或者称为操作).打个比方.在一个公司里面,整个运作就像一个系统.某个boss发布了一个命令,中层领导接到这个命令,然后指派给具体负责这个员工.整个流程很清晰吧.有一个需求,如何将这个流程固定下来,形成一个系统.我们只要抓住了重点:命令.将它抽取出来,其他的都迎刃而解了.抽取出命令,封装成一个独

详解Objective-C设计模式编程中对备忘录模式的运用

基本理解 这个模式有三个关键角色:原发器(Originator).备忘录(Memento).看管人(caretaker).三者的基本关系是:原发器创建一个包含其状态的备忘录,并传给看管人.看管人不知道如何与备忘录交互,但会把备忘录放在一个安全之处保管好. 备忘录(Memento):在 不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象回复到原先保存的状态. Originator(发起人):负责创建一个备忘录,用以记录当前时刻它的内部状态,并且可使用恢

详解Java设计模式编程中的里氏替换原则

定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型. 定义2:所有引用基类的地方必须能透明地使用其子类的对象. 问题由来:有一功能P1,由类A完成.现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成.新功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障. 解决方

详解Python设计模式编程中观察者模式与策略模式的运用

观察者模式 观察者模式:又叫发布订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时,会通知所有观察者对象,是他们能自动更新自己. 代码结构 class Topic(object): """主题类.保存所有观察者实例的引用,每个主题都可以有很多观察者 可以增加和删除观察者""" def __init__(self): self.obs = [] def Attach(self, ob): se