策略模式

Posted 嵌动初心(aaron)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了策略模式相关的知识,希望对你有一定的参考价值。

策略模式(Strategy Pattern)

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

原则

  • 针对接口(即超类型)编程,而不是针对实现编程;
  • 把会变化的部分取出并“封装”起来,好让其它部分不会受到影响;
  • 多用组合,少用继承;

注意:

  • 继承是为了减少代码量,如果由于类中的某些属性是多变的,那么在继承时,就要去重写这些动态属性,这种方式是不可取的。因为这样做不仅达不到减少代码量的目的,反而大大增加了代码量。这样的话,最好的解决方案就是利用策略模式,组合技术和面向接口编程(依赖倒转原则)。
  • 而继承要遵循里氏代换原则(子类代换父类后,程序的行为没有变化)当然,如果要达到程序行为没有变化,那么子类中就不要重写父类,这才是继承的正确打开方式。

案例一

题目:商场收银软件

功能: 1 计算购买商品的总价      2 商品拥有可选择的促销模式

案例分析

由题目知,商品的促销模式是变化的,可以增加也可以减少,所以,我们在设计商品类时,商品的促销模式的属性是不确定的,无法直接指定(在不同的时期,同一件商品可能会有不同的促销模式,不可能固定成同一个促销模式)。综上所述,需要利用策略模式,动态的将促销模式添加到商品类属性中。

 案例代码

#!/usr/bin/env python
# _*_ coding utf-8 _*_
#Author: aaron


#####################################
#              低层模块              #
#####################################
import abc

class CashSuper(metaclass=abc.ABCMeta):
    ‘‘‘促销策略抽象类‘‘‘
    @abc.abstractmethod
    def algorithem_interface(self, price):
        ‘‘‘算法接口‘‘‘


class Cashnormal(CashSuper):
    ‘‘‘不做促销类‘‘‘
    def __init(self):
        pass

    def algorithem_interface(self, price):
        ‘‘‘算法策略‘‘‘
        return price


class CashRebate(CashSuper):
    ‘‘‘折扣促销类‘‘‘
    def __init__(self,rebate):
        self.rebate = rebate

    def algorithem_interface(self, price,):
        ‘‘‘算法策略‘‘‘
        self.price = price * self.rebate
        return self.price


class CashReturn(CashSuper):
    ‘‘‘现金返利策略‘‘‘
    def __init__(self,money_conditon, money_return):
        self.money_condition = money_conditon
        self.money_return = money_return

    def algorithem_interface(self, price):
        if price >= self.money_condition:
            self.price = price - int(price/self.money_condition) * self.money_return
        return self.price


#####################################
#              高层模块              #
#####################################
class Product(object):
    ‘‘‘商品类‘‘‘

    def __init__(self, price, number, strategy):
        self.price = price
        self.number = number
        self.strategy = strategy   #促销策略对象
        self.normal_total = self.price * self.number

    def cash_total(self):
        self.money_total = self.strategy.algorithem_interface(self.normal_total)  #依赖倒转原则

    def show_price(self):
        print(‘单价:%f\t数量:%d\t正常价:%f\t促销价:%f‘
              %(self.price, self.number, self.normal_total, self.money_total))


class ProductFactory(object):
    ‘‘‘工厂类‘‘‘
    def product(self):
        choice = input(‘1 正常收费  2 满300返100  3 打8折\n请输入选择:‘)
        if choice == ‘1‘:
            return Product(400, 2, Cashnormal())
        elif choice == ‘2‘:
            return Product(400, 2, CashReturn(300, 100))
        elif choice == ‘3‘:
            return Product(400, 2, CashRebate(0.8))


if __name__ == ‘__main__‘:
    factory = ProductFactory()
    product = factory.product()
    product.cash_total()
    product.show_price()

在这里,我使用的组合技术时,并没有设计一个商品的父类,是直接定义了一个商品促销模式对象的静态属性。当然也可以将调用策略类接口再次用父类封装。子类中继承父类设置促销模式动态属性来设置促销模式对象的静态属性。(当然,这里大家看不懂就算了,这主要是给我自己看的,到底是什么意思,案例二,就是利用我说的这种方式来实现的)。

案例二

题目

现在需要实现几种鸭子,每种鸭子都有不同的特征(display)、飞行方式(fly)和发声方式(quack);

案例分析

首先我们需要建一个鸭子超类(Duck),然后在各种鸭子子类(MallardDuck, RedheadDuck, RubberDuck, DecoyDuck)中实现对应的方法;

每种鸭子的外观都不一样,因此display可留到子类中实现,即每增加一种鸭子类型,都必须重写一次display方法;
但是飞行和发声的方式就那么几种,如果按照display的方式处理,即便有些鸭子类型具有相同的行为方式也需要逐个重写,就会有大量重复代码;
如果采用继承方式,继承的子类如果相同则不用重写,但是不同的还是要重写,仍然没解决问题;

按照策略模式的原则,我们应该将行为方式当作独立算法看待,从鸭子类中独立出来,并提供统一接口;
这样的话,以后增加算法以及将某类鸭子和某种行为绑定会变得很容易;

#!/usr/bin/env python
# _*_ coding utf-8 _*_
#Author: aaron


class Duck:
    def display(self):
        pass

    def setFlyBehavior(self, fb):
        self.flyBehavior = fb

    def setQuackBehavior(self, qb):
        self.quackBehavior = qb

    def performQuack(self):
        self.quackBehavior.quack()

    def performFly(self):
        self.flyBehavior.fly()


class FlyBehavior:
    def fly(self):
        pass


class FlyWithWings(FlyBehavior):
    def fly(self):
        print("Fly with wings.")


class FlyNoWay(FlyBehavior):
    def fly(self):
        print ("Fly no way.")


class QuackBehavior:
    def quack(self):
        pass


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

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


class MuteQuack(QuackBehavior):
    def quack(self):
        print ("nothing")


class MallardDuck(Duck):
    def __init__(self):
        self.setFlyBehavior(FlyWithWings())
        self.setQuackBehavior(Squeak())

    def display(self):
        print ("MallardDuck")


class RedheadDuck(Duck):
    def __init__(self):
        self.setFlyBehavior(FlyWithWings())
        self.setQuackBehavior(Quack())

    def display(self):
        print ("RedheadDuck")


class RubberDuck(Duck):
    def __init__(self):
        self.setFlyBehavior(FlyNoWay())
        self.setQuackBehavior(MuteQuack())

    def display(self):
        print ("RubberDuck")


class DecoyDuck(Duck):
    def __init__(self):
        self.setFlyBehavior(FlyWithWings())
        self.setQuackBehavior(MuteQuack())

    def display(self):
        print ("DecoyDuck")


for n in MallardDuck(),RedheadDuck(),RubberDuck(),DecoyDuck():
    n.display()
    n.performFly()
    n.performQuack()
    #print

n.setFlyBehavior(FlyNoWay())
n.setQuackBehavior(Quack())
n.display()
n.performFly()
n.performQuack()

  

以上是关于策略模式的主要内容,如果未能解决你的问题,请参考以下文章

Redis实现分布式锁(设计模式应用实战)

用于从 cloudkit 检索单列的代码模式/片段

代码片-策略模式+工厂模式

代码片-策略模式+工厂模式

代码片-策略模式+工厂模式

代码片-策略模式+工厂模式