0
点赞
收藏
分享

微信扫一扫

设计模式:策略模式

JakietYu 2022-01-26 阅读 102
策略模式

背景

有一款鸭子游戏,系统中有很多种类的鸭子,所有鸭子都会游泳和呱呱叫。类图如下:

现在需要给鸭子添加飞行动作,让鸭子可以飞起来。

第1版实现

在父类Duck中新增fly方法,实现鸭子的飞行动作。

游戏运行之后发现,有一只橡皮鸭也飞了起来,橡皮鸭怎么会飞呢?

问题:并不是所有的鸭子都会飞,如果让不会飞的鸭子拥有飞行动作就会很奇怪

这个好解决:在所有不会飞的鸭子类中重写fly方法,什么也不做

如果系统中还有N(可以想象N很大)种鸭子不会飞,就得重写N个类,工作量好像有点大

那有没有一种方法,既可以让部分鸭子飞,又不用重写N个类呢?

第2版本实现

从第1版实现中的问题可知:对鸭子而言,飞行动作不是一个固有行为,并不是所有的鸭子都会飞,所以由父类实现是不合理的。对于这种变化的行为,可以考虑从系统中剥离出来。

先声明一个接口:FlyAction

再实现两个具体的飞行类:FlyWithWings和FlyNoWay

 然后在父类Duck中新增1个FlyAction属性和2个方法(Objective-C)

@property (nonatomic, strong) id<FlyAction> flyAction;

- (void)setFlyAction:(id<FlyAction>)flyAction {
   _flyAction = flyAction;
}

- (void)performFly {
    if ([self.flyAction respondsToSelector:@selector(fly)]) {
        [self.flyAction fly];
    }
}

 最后,在使用鸭子类的地方,给鸭子动态设置不同的飞行动作

- (void)test {
    // 会飞的鸭子
    Duck *duck1 = [RedHeadDuck new];
    [duck1 setFlyAction:[FlyWithWings new]];
    [duck1 performFly];
    
    // 不会飞的鸭子
    Duck *duck2 = [RubberDuck new];
    [duck2 setFlyAction:[FlyNoWay new]];
    [duck2 performFly];
}

后续如果新增一种新的飞行动作,也不需要修改鸭子类中的代码。

其实,这种设计就是采用了策略模式。 

策略模式

策略模式的结构:

(1)Strategy:抽象策略类,定义公共接口,Context类通过该接口调用具体策略

(2)ConcreteStrategy:具体策略类,实现具体的策略算法

(3)Context:上下文,策略的使用者,持有Strategy对象的引用

对于鸭子系统而言,FlyAction就是Strategy,鸭子可以用翅膀飞,可以借助飞行器,也可以不会飞,这些都是一种策略,而Duck就是Context,可以使用不同的飞行策略。

策略模式的定义:定义了一系列算法,并把它们都封装起来,使它们之间可相互替换。

总结

什么情况下适合使用策略模式呢?

第1种情况:如果系统中很多相关的类仅仅是行为有差异,则可以将这些行为抽象为策略

第2种情况:一个类的多种行为通过条件语句实现,则可以将这些条件分支抽象为策略

举报

相关推荐

0 条评论