动态语言与设计模式

   C++语言的运行时多态性的基础是虚函数机制,指向基类的指针可以指向它的任何派生类,在实现设计模式时充分利用了C++这一特性,结合继承机制,建立类和对象的层次关系,使C++最大程度的具有动态特性,将绑定关系尽可能推迟到运行时确定。

 

   在GoF的23种模式中,部分设计模式是专门为静态语言提出的,有些模式在动态语言中语言一级就提供直接的支持,如Command模式,动态语言提供的函数式编程将函数本身看作是类对象。

 

   1. 工厂模式

 

   用C++语言实现的工厂方法仍然存在局限性,这种局限性不利于构建可复用的软件。因为创建所有的产品类型都是通过Make接口的,为了保持Make接口的 返回值对所有产品的兼容性,就不得不迫使所有产品类型必须继承于一个公共的基类,然后Make接口返回该基类,这样保证了Make返回的类型都可以转换成 特定的产品类型。但是,同一系列不同类型的产品在逻辑上可能不存在明确的公共基类,比如MazeFactory中的Maze和Wall,而且,使用公共基类导致了大量的向下强制转换,这种转换往往是不安全的,有时还不可行。

 

  Pyhon语言的动态类型特性为解决该问题提供良好的方案,Python允许一个变量在运行时绑定到不同类型的对象上,所以不必要求不同类型的产品具有公 共基类,Make接口不必声明其返回类型,调用时具体的返回值类型在运行时交给解释器去完成。Python实现工厂方法的代码如下:

 

  class Maze:…
class Wall:…

class MazeFactory(object):
    def make(self, typename, *args):
         if typename == 'maze': return Maze()
         elif typename == 'wall': return Wall()
         elif typename == 'room':
               return Room(args[0])
         elif typename == 'door': ]
               return Door(args[0], args[1]) 
self是MazeFactory实例对象的引用参数,typename标识创建对象的类型,*args是创建具体对象时所需的参数列表。魔法迷宫的代码
 
class EnchantedFactory(MazeFactory):
    def make(self, typename, *args):
        if typename == 'room': return EnchantedRoom(args[0] )
        elif typename == 'door': return EnchantedDoor(args[0],args[1])
        else: return super(EnchantedFactory, self).make(typename, args) 
make方法中的return super(EnchantedFactory, self).make(typename, args)表示调用父类的操作创建其它类型的对象。
那么创建一个具体的EnchantedFactory实例的代码:
mf = EnchantedFactory()
mz = mf.make('maze')
r1 = mf.make('room', 1)
r2 = mf.make('room', 2)
dr = mf.make('door', r1, r2)
当需要在MazeFactory添加一个Trap新类型时,只需要在Make方法中添加标示新类型的参数即可:
      elif typename == “trap”: return Trap()
这种做法不但保持了MazeFactory对外接口的稳定性,而且不需要类型的向下转换。但这里同样存在一个问题:每添加一个新类型,都要修改Make的实现代码。能不能不用修改Make的代码即可添加一个新类型呢?class Maze:…
class Wall:…

class MazeFactory(object):
    def make(self, typename, *args):
         if typename == 'maze': return Maze()
         elif typename == 'wall': return Wall()
         elif typename == 'room':
               return Room(args[0])
         elif typename == 'door': ]
               return Door(args[0], args[1]) 
self是MazeFactory实例对象的引用参数,typename标识创建对象的类型,*args是创建具体对象时所需的参数列表。魔法迷宫的代码
 
class EnchantedFactory(MazeFactory):
    def make(self, typename, *args):
        if typename == 'room': return EnchantedRoom(args[0] )
        elif typename == 'door': return EnchantedDoor(args[0],args[1])
        else: return super(EnchantedFactory, self).make(typename, args) 
make方法中的return super(EnchantedFactory, self).make(typename, args)表示调用父类的操作创建其它类型的对象。
那么创建一个具体的EnchantedFactory实例的代码:
mf = EnchantedFactory()
mz = mf.make('maze')
r1 = mf.make('room', 1)
r2 = mf.make('room', 2)
dr = mf.make('door', r1, r2)
当需要在MazeFactory添加一个Trap新类型时,只需要在Make方法中添加标示新类型的参数即可:
      elif typename == “trap”: return Trap()
这种做法不但保持了MazeFactory对外接口的稳定性,而且不需要类型的向下转换。但这里同样存在一个问题:每添加一个新类型,都要修改Make的实现代码。能不能不用修改Make的代码即可添加一个新类型呢?class Maze:…
class Wall:…

class MazeFactory(object):
    def make(self, typename, *args):
         if typename == 'maze': return Maze()
         elif typename == 'wall': return Wall()
         elif typename == 'room':
               return Room(args[0])
         elif typename == 'door': ]
               return Door(args[0], args[1]) 
self是MazeFactory实例对象的引用参数,typename标识创建对象的类型,*args是创建具体对象时所需的参数列表。魔法迷宫的代码
 
class EnchantedFactory(MazeFactory):
    def make(self, typename, *args):
        if typename == 'room': return EnchantedRoom(args[0] )
        elif typename == 'door': return EnchantedDoor(args[0],args[1])
        else: return super(EnchantedFactory, self).make(typename, args) 
make方法中的return super(EnchantedFactory, self).make(typename, args)表示调用父类的操作创建其它类型的对象。
那么创建一个具体的EnchantedFactory实例的代码:
mf = EnchantedFactory()
mz = mf.make('maze')
r1 = mf.make('room', 1)
r2 = mf.make('room', 2)
dr = mf.make('door', r1, r2)
当需要在MazeFactory添加一个Trap新类型时,只需要在Make方法中添加标示新类型的参数即可:
      elif typename == “trap”: return Trap()
这种做法不但保持了MazeFactory对外接口的稳定性,而且不需要类型的向下转换。但这里同样存在一个问题:每添加一个新类型,都要修改Make的实现代码。能不能不用修改Make的代码即可添加一个新类型呢?原型模式(Prototype)提供了一种更好的解决方案——编制产品字典。

 

  2. 原型模式(Prototype)

 

  原型模式使用一个原型实例指定创建对象的类型,并且通过复制原型创建新的对象。原型模式的优点是可以在运行时动态的增加和删除产品类型,减少了子类化,还 可以动态的配置应用程序。使用原型管理器(Prototype Manager)可以方便实现运行时类型的增加和删除,管理器中有个类型的注册表,注册表是个关联存储结构的表,对于给定类型的键值可以唯一确定一个类 型,增加一个新类型时就是在表中注册该类型,客户程序在使用一个类型前先访问注册表检索它的原型。实现迷宫MazeFactory原型的Python代码 如下:
 
class MazeFactory:
   def __init__(self):
        self.index = {'maze': Maze,
                      'wall': Wall,
                      'room': Room,
                      'door': Door}
   def make(self, typename, *args):
      return apply(self.index[typename], args)
   def registtype(self, typename, instance):
      self.index[typename] = instance
   def unregisttype(self, typename):
      del self.index[typename] 
在 MazeFactory中,数据成员self.index={…}是个字典类型,存放MazeFactory产品类型,方法registtype和 unregisttype实现了产品类型的动态增加和删除,参数instance表示需要添加或删除类型的实例名。假如创建了一个MazeFactory 实例mf=MazeFactory(),实例Trap的定义如下:
 
class Trap:
    def __init__(self, radius, height):
       self.radius = radius
       self.height = height
    … 
向mf中添加实例Trap的代码:mf.registtype(‘trap’,Trap),而相应的删除代码为mf.unregisttype(‘trap’,Trap)。
   显然,这种实现方式便于动态管理类型,具有良好的可扩展性。

 

  3. 单件模式提供了一种将系统中类的实例个数限制为一个的机制,保证了一个类只有一个实例,并提供了该实例的一个全局访问点。程序的不同模块通常会共享同一个 对象。单件模式隐藏了实际的全局变量,对外提供了访问的接口,是一种很好的访问全局变量的方法。首先我们来看一下C++是怎样实现单件模式的。 Singleton类的定义如下:
 
class Singleton {
public:
    static Singleton* Instance();
protected:
    Singleton();
private:
    static Singleton* _instance;
};
//对应的实现:
Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance ()
{
    if (_instance == 0)
    {
        _instance = new Singleton;
    }
    return _instance;

在 单件类中,静态数据成员_instance指向已经创建的实例,静态成员函数Instance()为单件类提供了全局访问点,客户程序只能通过 Instance()接口创建单件类,如果_instance不为0,则直接返回已创建的实例,注意Singleton类的构造函数声明为 protected属性防止客户程序不通过Instance()接口创建它,保证了单件类的唯一性。
Python语言中的类和函数的定义可以在运行时改变,借助这一语言特性给出实现Singleton模式Python版本:
 
class Singleton(object):
   def __new__(cls):
      cls.instance = object.__new__(cls)
      cls.__new__ = cls.Instance
      cls.instance.init()
      return cls.instance
   def Instance(cls,type):
      return cls.instance
   Instance = classmethod(Instance)
   def init(self):
       pass 

 

  语句:cls.__new__ = cls.getInstance是将getInstance赋给__new__方法,执行后,Singleton类的__new__方法变成了 getInstance。第一次创建Singleton实例对象时,调用__new__方法生成Singleton的一个新的实例,试图再次创建 Singleton实例对象时,调用的__new__的方法实际上被“偷偷的“调包成getInstance,__new__方法的代码不再被执行,而是 执行getInstance方法返回已经创建的实例对象cls.instance,从而保证了只存在一个Singleton实例对象。 cls.instance.init()说明了__new__方法在__init__之前调用,为了进一步初始化Singleton子类。

 

  4. 代理模式(Proxy)
从面向对象设计的角度看,限制访问属性给一些旧问题提供了一种新的解决办法。代理模式就是一个很好的例子。代理模式用于隔离对象和访问它的客户,比如引用计数、不同等级的授权访问以及对象的惰性赋值等。代理模式的结构如下: 客户程序不需要直接访问实际的对象,换句话说,代理替代了实际的对象,客户通过代理去访问实际的对象。在C++中,这就意味着Proxy和 RealSubject必须要有一个公共的基类。在Python中,通过提供相同的方法接口,Proxy可以达到冒充Subject的效果。以下 Python代码中Proxy类是基于小型的通用包装类,它的主要功能就是为多个特定代理的实现提供一个基类,在Proxy类中可以重载 __gettattr__方法处理不同的方法。
 
#Proxy Base Class
class Proxy:
    def __init__( self, subject ):
        self.__subject = subject
    def __getattr__( self, name ):
        return getattr( self.__subject, name )
#Subject class
class RGB:
    def __init__( self, red, green, blue ):
        self.__red = red
        self.__green = green
        self.__blue = blue
    def Red( self ):
        return self.__red
    def Green( self ):
        return self.__green
    def Blue( self ):
        return self.__blue   
# More specific proxy implementation
class NoBlueProxy( Proxy ):
    def Blue( self ):
        return 0     
考虑以下情况:首先我们需要直接访问RGB类的实例对象,然后使用一个通用的代理实例作为一个包装类,最后传递给NoBlueProxy类:
>>> rgb = RGB( 100, 192, 240 )
>>> rgb.Red()
100
>>> proxy = Proxy( rgb )
>>> proxy.Green()
192
>>> noblue = NoBlueProxy( rgb )
>>> noblue.Green()
192
>>> noblue.Blue()
0
代理模式在Python中应用很广泛,Python语言提供的机制中有一些就是代理模式实现的,比如垃圾收集中的简单引用计数。

 

  5. 命令模式(Command)
用过集成开发环境的人都知道,开发基于窗口图形界面的应用程序时,一般要用到按钮和菜单等控件对象响应用户的输入,但 在集成环境的工具箱提供的按钮和菜单并没有显式地实现该请求,也就是按钮和菜单不知道关于请求的操作和请求的接受者的任何信息,这些请求特定于具体应用, 只用控件的使用者才知道该由哪个对象响应哪个操作,工具箱的设计者无法知道请求的接受者和执行的操作。那么工具箱的设计者是如何实现按钮和菜单的这种功能 的呢?用Command模式。
Command模式解耦了调用操作的对象(如按钮、菜单)和实现该操作的对象(如文档)。C++利用继承组合机制实 现Command模式,通过定义一个带有Execute接口的Command抽象类,特定应用相关的Command派生于此类,在Command类的子类 显式定义接受者的对象。Command类在调用操作的对象(Invoker)和实现该操作的对象(Receiver)之间充当了桥梁作用, Invoker请求某个Command类,由Command类的Execute接口执行Receiver的具体操作并将返回结果告诉Invoker,对于 Invoker根本不知道是谁执行了该操作,也不需要知道,从而实现了两者的解耦。而Python具有运行时可以改变类的结构、函数的定义的动态特性,很 简单地就实现了Command模式:
 
class Button:
    def click(self):pass
class document:
    def open(self):
        print "open document..."
btn = Button()
doc = document()
btn.click = doc.open 
执行btn.click()时实际上相当于调用了doc.open()的方法,实现了Button和document两者的解耦,比C++的继承组合机制要简单。
有 时一个按钮要求执行一系列命令,这种宏命令(MacroCommand)在应用中也是很常见的。Python支持lamda匿名函数定义,运用函数式编程 方式也可以很简便的实现MacroCommand模式。我们先来看看用C++是怎样实现的。C++用一个命令列表管理命令系列,执行宏命令实际上是遍历一 次命令列表:
 
class Command {
public:
    virtual ~Command();
    virtual void Execute() = 0;
protected:
    Command();
};
class MacroCommand : public Command {
public:
    MacroCommand();
    virtual ~MacroCommand();
    virtual void Add(Command*);
    virtual void Remove(Command*);
    virtual void Execute();
private:
    List<Command*>* _cmds;//命令列表
};
void MacroCommand::Execute ()
{
    ListIterator<Command*> i(_cmds);
for (i.First(); !i.IsDone(); i.Next())  //遍历命令列表
{
        Command* c = i.CurrentItem();
        c->Execute();
    }

在Python中,假设已经定义了一个Button类和一个Document类,Button类有一个Click方法,Document包含Paste和Replace方法,以下代码实现了点击按钮后同时执行Paste和Replace操作:
 
doc = Document()
btn = Button()
macrcocmd = lambda cmds : map(lambda cmd:cmd(),cmds)
btn.Click = lambda: macrcocmd([doc.Paste, doc.Replace]) 
函 数map是个Python内置函数,其作用是将列表cmds作为参数传递给匿名函数lambda cmd : cmd()执行并返回一个元组作为匿名函数macrocmd的参数,调用btn.Click()执行了匿名函数macrocmd(),该函数接受元组 [doc.Paste, doc.Replace] 作为它的输入参数,执行doc.Paste()和doc.Replace()命令。

 

 

  总结:

  Python的灵活性和动态性为实现一些不同的、优美的解决方案提供了一个良好的基础。Python的无类型化解决了静态语言实现工厂方法中需要不安全的 强制类型转换等问题,既减少了程序中类的设计,又避免了静态语言中的向下转换问题。原型模式为创建不同类型的对象提供一种更好的方法,利用了Python 可以运行时改变类的定义的特性,可以动态地增删类型,提高了程序的可扩展性。而单件模式则利用了类的静态方法__new__以及动态改变类的结构和定义的 特点,巧妙地实现了限制了单件类的实例对象个数的功能。在Proxy模式中,充分体现了Python中同一个类的多个实例对象之间可以拥有不同的结构以及 可以监视和限制属性访问的语言机制,这些机制为个实现多个通用类提供了一个相当完美的解决方法。在C++中不支持匿名函数,命令模式初步展现了 Python中lamda匿名函数在实现某些问题的简便性。其他的模式,如职责链(Chain Of Responsibility)、策略模式(Strategy)、装饰模式(Decorator),利用Python语言特性,也可以写出Python的 实现版本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MQL语言是一种专门用于MT4和MT5外汇交易平台的编程语言,它可以用于设计和开发智能交易系统(EA)。MQL语言设计模式主要包括以下几种: 1. 趋势跟随模式:这种模式基于市场趋势的方向进行交易。当市场处于上升趋势时,交易系统会开仓做多;当市场处于下降趋势时,交易系统会开仓做空。这种模式的目标是捕捉到趋势的延续,并在趋势结束时平仓。 2. 反转模式:这种模式基于市场价格的反转进行交易。当市场价格达到一定的极值点时,交易系统会开仓反向交易。例如,当市场价格达到高点时,交易系统会开仓做空。这种模式的目标是捕捉到价格反转的机会,并在反转结束时平仓。 3. 均值回归模式:这种模式基于市场价格的回归进行交易。当市场价格偏离其均值时,交易系统会开仓反向交易,以期望价格回归到均值附近。例如,当市场价格偏离均值过多时,交易系统会开仓做反向交易。这种模式的目标是捕捉到价格回归的机会,并在回归完成时平仓。 4. 市场制造商模式:这种模式基于市场制造商的行为进行交易。市场制造商通常会在市场制造波动,以吸引交易者进入市场。交易系统可以通过观察市场制造商的行为,例如订单流量和价格变动,来进行交易。这种模式的目标是捕捉到市场制造商的行为,并在合适的时机进行交易。 以上是MQL语言的一些常见设计模式,交易者可以根据自己的交易策略和风险偏好选择适合自己的模式进行交易。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值