设计模式 #1: 策略模式

Posted on 2016-7-6 in Code

这是我有关图书 Head First 设计模式 的笔记,因为我刚开始学 Java,很多特性还不熟,所以这里选择用 Python 来实现。

定义

策略模式(strategy pattern)定义了算法簇,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

起始例子

class Duck(object):
    def quack(self):
        print "quack"
    def swim(self):
        print "swim"
    def display(self):
        raise NotImplementedError("abstract display")


class MallardDuck(Duck):
    def display(self):
        print "green"


class RedheadDuck(Duck):
    def display(self):
        print "red"

现在我们要让鸭子能飞,但并不是所有的鸭子都能飞,比如玩具橡皮鸭子,而且玩具玩具橡皮鸭子也不会呱呱叫(quack),而应该是吱吱叫(squeak)。 在超类添加方法并不是一个好的选择,因为它将fly继承给了所有的子类。

问题

使用继承并不能很好的解决问题,因为鸭子的行为在子类里不断地改变,并且让所有的子类都有这些行为是不恰当的。

书中的解决办法

我们应该在鸭子类中包含设定行为的方法,这样就可以在”运行时“动态地改变鸭子的行为。

实际情况下,我们应该把以下类写到不同的文件中。

class FlyBehavior(object):
    '''FlyBehavior interface class'''
    def fly(self):
        raise NotImplementedError('abstract FlyBehavior')


class FlyWithWings(FlyBehavior):
    def fly(self):
        print "I'm flying!!"


class FlyNoWay(FlyBehavior):
    def fly(self):
        print "I can't fly"


class QuackBehavior(object):
    '''QuackBehavior interface class'''
    def quack(self):
        raise NotImplementedError('abstract QuackBehavior')


class Quack(QuackBehavior):
    def quack(self):
        print "Quack"


class Squeak(QuackBehavior):
    def quack(self):
        print "Squeak"


class MuteQuack(QuackBehavior):
    def quack(self):
        print "<< Silence >>"


class Duck(object):
    '''Duck super class'''
    def set_fly_behavior(self, fly_behavior):
        self.fly_behavior = fly_behavior

    def set_quack_behavior(self, quack_behavior):
        self.quack_behavior = quack_behavior

    def display(self):
        raise NotImplementedError("abstract display")

    def perform_fly(self):
        self.fly_behavior.fly()

    def perform_quack(self):
        self.quack_behavior.quack()

    def swim(self):
        print "All ducks float, even decoys."


class MallardDuck(Duck):
    def __init__(self):
        super(MallardDuck, self).__init__()
        self.set_fly_behavior(FlyWithWings())
        self.set_quack_behavior(Quack())

    def display(self):
        print "green"


class RedheadDuck(Duck):
    def __init__(self):
        super(RedheadDuck, self).__init__()
        self.set_fly_behavior(FlyWithWings())
        self.set_quack_behavior(Quack())

    def display(self):
        print "red"


class RubberDuck(Duck):
    def __init__(self):
        super(RubberDuck, self).__init__()
        self.set_fly_behavior(FlyNoWay())
        self.set_quack_behavior(Squeak())

    def display(self):
        print "rubber"

if __name__ == '__main__':
    # mini duck simulator
    mallard = MallardDuck()
    mallard.perform_quack()
    mallard.perform_fly()

设计原则

  • 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  • 针对接口编程,而不是针对实现编程 (注:接口是 Java 中的特性,Python 中并没有,但是我们可以有类来实现)。
  • 多用组合,少用继承:“HAS-A”,而不是“IS-A”。