swift设计模式:(一)策略模式(Strategy Pattern)

写在文章前的话
我们在重构代码时,往往会用到设计模式,文章的案例主要是来自《Head First Design Patterns》或者是参考其他博主的案例,需要下载pdf文件的,可以点击这个链接:
链接: 《Head First Design Patterns》中文pdf
提取码: jh89

策略模式

定义:将不同的策略(算法)进行封装,让他们之间可以相互的替换,此模式让测试的变化独立于试用策略的用户

策略模式如何运用,通过下面这个案例来讲解。

一、实现一个鸭子的游戏

需求:模拟鸭子游戏,在游戏中会出现各种鸭子,一边游泳,一遍呱呱叫。

看到设个需求,我们一般直接的想法是,设计了一个鸭子基类Duck,包含鸭子的呱呱叫、游泳以及具体的展现方法,并让各种鸭子继承此基类,由于不同的鸭子会有不同的展现,所以会重写基类的display方法。

类“类图”图示如下:
swift设计模式:(一)策略模式(Strategy Pattern)_第1张图片
上面的图是一个简化的类“类图”,Duck 是一个父类,其他类型的鸭子继承自 Duck。目前这么实现是没有问题的。

代码实现:

class Duck{
    func swim(){
        print("鸭子游泳喽~")
    }
    
    func quack(){
        print("鸭子呱呱叫")
    }
    
    func display(){
    }
}
class MallarDuck : Duck{
    override func display() {
        print("我是绿头鸭子")
    }
}
class RedHeadDuck:Duck{
    override func display() {
        print("我是红头鸭子")
    }
}
class RubberDuck:Duck{
    override func display() {
        print("橡皮鸭")
    }
}

二、鸭子游戏增加新需求

需求1:鸭子能飞

接下来,新需求来了:现在我们的让鸭子能飞

还是按着上面的思路,在基类增加一个 fly() 方法
swift设计模式:(一)策略模式(Strategy Pattern)_第2张图片
但是,这样做导致了一个严重的后果,所有的鸭子都会继承 fly()方法,如果我们的鸭子是橡皮鸭…橡皮鸭会飞…额…虽然看起来很有趣,但这是个不符合常理的现象,按着常理来说,橡皮鸭是不会飞的,所以我们这样实现是又问题的。

由于一些假的鸭子是不能飞的,所以要改变上面的实现方式,有两种解决办法

1、在基类中添加fly(),在不会飞的鸭子中重新fly,但是这样的话,会导致子类中存在些无用的方法
2、使用接口即协议,定义fly(),在需要实现 fly() 的鸭子子类中,实现接口即可,但是也会导致重复的产生

1、使用swift协议延展实现

将飞的行为定义为一个协议,通过协议的扩展实现fly()方法,会飞的鸭子的子类新搜协议即可,不会飞的鸭子不用遵守该协议
swift设计模式:(一)策略模式(Strategy Pattern)_第3张图片
具体代码实现:

protocol Flyable {
    func fly()
}
extension Flyable{
    func fly(){
        print("我是会飞的鸭子,我用翅膀飞")
    }
}
class Duck{
    func swim(){
        print("鸭子游泳喽~")
    }
    
    func quack(){
        print("鸭子呱呱叫")
    }
    
    func display(){
    }
}
//用绿头鸭实现会飞的功能
class MallarDuck : Duck, Flyable{
    override func display() {
        print("我是绿头鸭子")
    }
}
class RedHeadDuck:Duck{
    override func display() {
        print("我是红头鸭子")
    }
}
class RubberDuck:Duck{
    override func display() {
        print("橡皮鸭")
    }
}

2、使用多态、行为代理即策略模式

在设计模式中有不同的设计原则,策略模式主要参考一下3条原则

1、 找出程序中可能变化的地方,并且把它们独立出来,不要和不变的代码混在一起。
2、针对接口编程,而不是针对实现编程
3、多用组合,少用继承

根据这条设计原则,然后结合上述示例,我们使用“策略模式”来实现鸭子会飞的行为。
swift设计模式:(一)策略模式(Strategy Pattern)_第4张图片
首先将飞行行为使用接口封装,然后将不同的飞行模式实现接口函数

//飞的行为协议
protocol Flyable {
    func fly()
}
//使用翅膀飞的类
class FlyWithWings:Flyable{
    func fly() {
        print("我是会飞的鸭子,我用翅膀飞呀飞")
    }
}
//什么都不会飞
class FlyNoWay:Flyable{
    func fly() {
        print("我是不会飞的鸭子")
    }
}

其次,在Duck类中定义飞行为的委托代理者,并创建可以动态更改飞行行为的方法,并实现执行飞的行为的函数

class Duck{
    //添加行为委托代理者
    var flyBehavior : Flyable! = nil
    
    func setFlyBehavior(_ flyBehavior : Flyable){
        self.flyBehavior = flyBehavior
    }
    func swim(){
        print("鸭子游泳喽~")
    }
    
    func quack(){
        print("鸭子呱呱叫")
    }
    
    func display(){
    }
    
    //执行飞的行为
    func performFly(){
        guard self.flyBehavior != nil else {
            return
        }
        self.flyBehavior.fly()
    }
}

最后,鸭子子类中只需要在初始化时设置飞的类型即可

//用绿头鸭实现会飞的功能
class MallarDuck : Duck{
    override init() {
        super.init()
        self.setFlyBehavior(FlyWithWings())
    }
    override func display() {
        print("我是绿头鸭子")
    }
}
class RedHeadDuck:Duck{
    override init() {
        super.init()
        self.setFlyBehavior(FlyWithWings())
    }
    override func display() {
        print("我是红头鸭子")
    }
}
class RubberDuck:Duck{
    override init() {
        super.init()
        self.setFlyBehavior(FlyNoWay())
    }
    override func display() {
        print("橡皮鸭")
    }
}

需求2:增加模型鸭子,且会飞

在使用了策略模式的基础上,对代码进行扩充时非常简单的。

我们只需要创建 模型鸭子 继承Duck 类,并在初始化中设置飞行类型即可

class ModelDuck : Duck{
    override init() {
        super.init()
        self.setFlyBehavior(FlyWithWings())
    }
    override func display() {
        print("鸭子模型")
    }
}

需求3:给模型鸭子装发动机,支持他飞

创建一个发动机飞行的类,实现接口函数

class FlyAutomaticPower : Flyable{
    func fly() {
        print("我是用发动机飞的鸭子")
    }
}

最后,测试是非常重要的,在使用设计模式重构的过程中,可以使用测试来检验功能是否正确

//    print("鸭子:使用延展")
//    let mallarDuck : MallarDuck = MallarDuck()
//    mallarDuck.fly()
    
    print("鸭子:使用接口")
    var duck : Duck = MallarDuck()
    duck.performFly()
    duck.setFlyBehavior(FlyNoWay())
    duck.performFly()
    print("-----创建一个模型鸭子,且会飞")
    duck = ModelDuck()
    duck.performFly()
    print("-----给模型鸭子装发动机,支持飞")
    duck.setFlyBehavior(FlyAutomaticPower())
    duck.performFly()
    print("\n")

测试结果swift设计模式:(一)策略模式(Strategy Pattern)_第5张图片

你可能感兴趣的:(设计模式)