美文网首页
设计模式之策略模式

设计模式之策略模式

作者: JohnnyB0Y | 来源:发表于2017-03-24 03:45 被阅读9次

    策略模式

    是什么?

    策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。

    怎么做?

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

    • 定义了一族算法(业务规则);
    • 封装了每个算法;
    • 这族的算法可互换代替(interchangeable)。

    遵守原则?

    • 封装变化。
    • 多用组合,少用继承。
    • 针对接口编程,不针对实现编程。
    第一步,区分客户和一族算法:

    以上面税收的例子,人就是客户。人可以是美国人、中国人。一族算法就是交个人所得税,有美国的算税方法,有中国特色的算税方法。

    第二步,抽象代码:
    // 客户的抽象
    class Human: NSObject {
    // 人类共同的属性和行为
    }
    
    class American: Human {
    // 美国人特殊的属性和行为
    }
    
    class Chinese: Human {
    // 中国人特殊的属性和行为
    }
    
    // 一族算法的抽象
    protocol PayTaxBehavior {
        // 交税的协议
        func payingTaxes()
    }
    
    class ChinaTax: NSObject, PayTaxBehavior {
        // 中国税收计算
        func payingTaxes() {
            print("中国税收计算!")
        }
    }
    
    class AmericanTax: NSObject, PayTaxBehavior {
        // 美国税收计算
        func payingTaxes() {
            print("美国税收计算!")
        }
    }
    
    
    第三步,组合调用:

    为什么示例代码是鸭子?因为我已经写好了,所以直接拷贝好了。

    1.0 一族算法的协议

    protocol FlyBehavior {
        func fly()
    }
    protocol QuackBehavior {
        func quack()
    }
    

    2.0 实现协议的算法类

    class FlyWithWings: NSObject, FlyBehavior {
        func fly() {
            print("I am fly with wings.")
        }
    }
    class FlyNoWay: NSObject, FlyBehavior {
        func fly() {
            print("I am fly no way.")
        }
    }
    class Quack: NSObject, QuackBehavior {
        func quack() {
            print("quack quack quack!")
        }
    }
    class Squeak: NSObject, QuackBehavior {
        func quack() {
            print("squeak squeak squeak!")
        }
    }
    class MuteQuack: NSObject, QuackBehavior {
        func quack() {
            print("Mute quack.")
        }
    }
    

    ** 3.0 用户的抽象类**

    class Duck: NSObject {
        // 遵守协议的一族算法对象,私有是为了不让子类直接访问。
        private var quackBehavior: QuackBehavior?
        private var flyBehavior: FlyBehavior?
    
        // 提供接口,让算法可互换代替
        public func setQuackBehavior( quackBehavior : QuackBehavior )
        {
            self.quackBehavior = quackBehavior
        }
        public func setFlyBehavior( flyBehavior : FlyBehavior )
        {
            self.flyBehavior = flyBehavior
        }
    
        // 可能某些鸭子没有的行为,提供接口调用封装好的算法。
        public func performFly()
        {
            flyBehavior?.fly()
        }
        public func performQuack()
        {
            quackBehavior?.quack()
        }
    
        // 鸭子共有的行为,可以直接继承。不同于父类的可以重写。
        public func swim()
        {
            print("I am swimming!!!")
        }
        public func name()
        {
            print("I am duck.")
        }
    }
    

    4.0 具体的用户

    class DuckA: Duck {
        override init() {
            super.init()
            // 子类有自己的默认行为。
            self.setFlyBehavior(flyBehavior: FlyWithWings())
            self.setQuackBehavior(quackBehavior: Quack())
        }
        public override func name() {
            print("I am duck A.")
        }
    }
    class DuckB: Duck {
        override init() {
            super.init()
            // B 也有自己的默认行为
            self.setFlyBehavior(flyBehavior: FlyWithWings())
            self.setQuackBehavior(quackBehavior: Squeak())
        }
        public override func name() {
            print("I am duck B.")
        }
    }
    class DuckC: Duck {
        override init() {
            super.init()
            // C 也有自己的默认行为
            self.setFlyBehavior(flyBehavior: FlyNoWay())
            self.setQuackBehavior(quackBehavior: MuteQuack())
        }
        public override func name() {
            print("I am duck C.")
        }
    }
    

    5.0 测试代码

    let duck = DuckC()
    
    // 我们有不一样的名字
    duck.name()
    // 但我们都会游泳
    duck.swim()
    
    // 调用默认行为
    duck.performFly()
    duck.performQuack()
    
    // 改变行为
    duck.setQuackBehavior(quackBehavior: Squeak())
    duck.setFlyBehavior(flyBehavior: FlyWithWings())
    
    // 调用改变后的行为
    duck.performFly()
    duck.performQuack()
    

    策略模式的优点

    • 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。
    • 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的策略中,使得它们易于切换,易于理解,易于扩展。
    • 策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
    • 在策略模式中利用组合和委托来让客户拥有执行算法的能力,这也是继承的一种更轻便的替代方案。

    缺点

    • 首先,使用策略模式会在程序中增加许多策略类或者策略对象,但实际上这比把它们负责的逻辑堆砌在客户中要好。
    • 其次,要使用策略模式,必须了解所有的策略,必须了解各个策略之间的不同点,这样才能选择一个合适的策略。比如,我们要选择一种合适的旅游出行路线,必须先了解选择飞机、火车、自行车等方案的细节。此时策略要向客户暴露它的所有实现,这是违反最少知识原则的。

    参考资料

    维基百科-策略模式

    相关文章

      网友评论

          本文标题:设计模式之策略模式

          本文链接:https://www.haomeiwen.com/subject/rtjxottx.html