通过C++和python场景实例理解装饰器设计模式。

来源:互联网 发布:chrome 插件 运行js 编辑:程序博客网 时间:2024/05/16 04:44

  参考文章:(1)http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html (2)http://en.wikipedia.org/wiki/Decorator_pattern

  装饰器是一个很著名的设计模式,充分利用了继承和聚合的优势,它以“装饰”的含义生动形象地描绘了“灵活、动态地为已经存在的对象添加额外的功能“的意图。

   下面分别选取两个场景,并分别对应C++语言和python语言,帮助读者理解这个模式。

场景一:咖啡制作

C++代码示例:

#include <iostream>#include <string> /* Abstract base class */// The abstract Coffee class defines the functionality of Coffee implemented by decoratorstruct Coffee {  virtual double getCost() = 0; // Returns the cost of the coffee  virtual std::string getIngredients() = 0; // Returns the ingredients of the coffee  virtual ~Coffee() = 0;};inline Coffee::~Coffee() { } /* SimpleCoffee class. */// Extension of a simple coffee without any extra ingredientsstruct SimpleCoffee : public Coffee {  virtual double getCost() {    return 1.0;  }   virtual std::string getIngredients() {    return "Coffee";  }}; /* Decorators */// Decorator Milk that adds milk to coffee.struct MilkDecorator : Coffee {  MilkDecorator (Coffee *basicCoffee)    : basicCoffee(basicCoffee) {  }   virtual double getCost() { // Providing methods defined in the abstract superclass    return basicCoffee->getCost() + 0.5;  }   virtual std::string getIngredients() {    return basicCoffee->getIngredients() + ", " + "Milk";  }private:  Coffee *basicCoffee;}; // Decorator Whip that adds whip to coffeestruct WhipDecorator : Coffee {  WhipDecorator (Coffee *basicCoffee)    : basicCoffee(basicCoffee) {  }   virtual double getCost() {    return basicCoffee->getCost() + 0.7;  }   virtual std::string getIngredients() {    return basicCoffee->getIngredients() + ", " + "Whip";  }private:  Coffee *basicCoffee;}; /* Test program */int main() {  SimpleCoffee s;  std::cout << "Cost: " << s.getCost() << "; Ingredients: " << s.getIngredients() << std::endl;   MilkDecorator m(&s);  std::cout << "Cost: " << m.getCost() << "; Ingredients: " << m.getIngredients() << std::endl;   WhipDecorator w(&s);  std::cout << "Cost: " << w.getCost() << "; Ingredients: " << w.getIngredients() << std::endl;   // Note that you can stack decorators:  MilkDecorator m2(&w);  std::cout << "Cost: " << m2.getCost() << "; Ingredients: " << m2.getIngredients() << std::endl;}

测试输出:

Cost: 1.0; Ingredients: CoffeeCost: 1.5; Ingredients: Coffee, MilkCost: 1.7; Ingredients: Coffee, WhipCost: 2.2; Ingredients: Coffee, Whip, Milk

场景二:为函数插入日志(Python)

在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。

decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。

装饰器的定义很是抽象,我们来看一个小例子。

def foo():    print 'in foo()' foo()

这是一个很无聊的函数没错。但是突然有一个更无聊的人,我们称呼他为B君,说我想看看执行这个函数用了多长时间,好吧,那么我们可以这样做

import timedef foo():    start = time.clock()    print 'in foo()'    end = time.clock()    print 'used:', end - start foo()

很好,功能看起来无懈可击。可是蛋疼的B君此刻突然不想看这个函数了,他对另一个叫foo2的函数产生了更浓厚的兴趣。

怎么办呢?如果把以上新增加的代码复制到foo2里,这就犯了大忌了~复制什么的难道不是最讨厌了么!而且,如果B君继续看了其他的函数呢?

使用如下装饰器模式可解决这个问题:

#-*- coding: UTF-8 -*-import time def foo():    print 'in foo()' # 定义一个计时器,传入一个,并返回另一个附加了计时功能的方法def timeit(func):         # 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装    def wrapper():        start = time.clock()        func()        end =time.clock()        print 'used:', end - start         # 将包装后的函数返回    return wrapper foo = timeit(foo)foo()

我们只需要在定义foo以后调用foo之前,加上foo = timeit(foo),就可以达到计时的目的,这也就是装饰器的概念,看起来像是foo被timeit装饰了。在在这个例子中,函数进入和退出时需要计时,这被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里,能减少大量重复代码。


具体C++和python在对待装饰器上的不同,还请读者自行体会。


1 0
原创粉丝点击