每天一种设计模式-- 策略模式

Posted 杯酒红尘

tags:

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

目的:将对象和行为解耦。由继承得来的行为,灵活性不够,行为是写死在类中的。如果需要修改,
只能修改原来的类。如果修改超类,则所有子类都受影响。如果修改子类,那么子类中会出现大量
重复代码。比如有十个子类,它们的行为与超类行为不同,则要修改十个子类。问题是,这十个子
类的行为是一致的,却无法将行为重用。将行为抽离出来,则可以达到共用的目的。

  1. 只需要在对象中包含一个行为对象,调用行为对象的方法来完成对应行为即可。

  2. 行为对象要实现特定行为的接口。

比如一个Person对象,有吃饭,睡觉的行为。当然,你可以说人的吃和睡,能有什么差别。是的,大
部分人都是一样的。但是,有的人,就细嚼慢咽,有的人,则狼吞虎咽,对于一种行为来说,这确实是
有差别的。有的人睡觉很安静,有的人睡觉打呼噜,还的的人睡觉睁着眼睛,这也是差别。具体什么样
的差别算差别,还是业务逻辑说了算。

这时,最基本也是最直接的方式,就是在Person类中实现默认的,普遍的吃饭和睡觉方法。然后子类中
那些特别的人,去覆盖对应的方法。这时候,问题来了,有的人睡觉很安静,吃饭狼吞虎咽;有的人睡觉
很安静,吃饭细嚼慢咽;有的人睡觉打呼噜,吃饭狼吞虎咽。。。。对于这些拥有不同行为的人,要
创建它们的实例,就得根据行为不同,组合出各种不同的类,类爆炸来了。

public class Person {

    public void sleep() {
        System.out.println("普通人睡觉");
    }
    
    public void eat() {
        System.out.println("普通人吃饭");
    }
}
class Snorer extends Person{
    public void sleep() {
        System.out.println("呼噜。。。呼噜。。。");
    }
}

class Huger extends Person{
    public void eat() {
        System.out.println("狼吞虎咽");
    }
}

// 更多形形色色的组合

策略模式很好的解决了这个问题。
将睡觉,吃饭这些行为分离出去,不在是Person类的方法。而是单独的行为对象。行为对象只需要实现
行为接口。睡觉这个行为对象,实现了睡觉行为接口,假设为: interface Sleep 这个接口中,只有
一个方法, void sleep(); 很明显,行为对象实现此接口,只需要实现sleep方法即可。吃饭行为对象
也是一样。

现在行为对象有了,怎么和Person对象联系起来呢?

需要在Person类内部创建一个实例变量: Sleep sleepBehavior;
将以前硬编码在Person类内部的 sleep,eat方法做下修改。

interface Sleep{
  void sleep();
}
interface Eat{
  void eat();
}
public class SnorerSleep implements Sleep{
  System.out.println("呼噜。。。呼噜。。。");
}
public class HugerEat implements Eat{
  System.out.println("狼吞虎咽");
}
public abstract class Person{
    Sleep sleepBehavior;
    Eat eatBehavior;
    public void sleep(){
        sleepBehavior.sleep();
    }
    public void eat(){
        eatBehavior.eat();
    }
}

public class Snorer extends Person{

  public Snorer(){
    this.sleepBehavior = new SnorerSleep();
  }
}

new Snorer().sleep(); // 呼噜。。。呼噜。。。

如果需要在运行时,动态的改变Person对象的行为,可以添加 sleepBehavior 和 eatBehavior 的setter
,调用之后,实例的行为就会发生变化。

这样,行为得到了复用,并且和对象解耦了。是不是更容易维护了?

缺点:

  1. 会产生很多策略类,但是相对原来的模式,要好很多。
  2. 需要了解所有的策略,才能作出正确的选择。但是,代码是咱们写的,这不是什么问题。有文档,更简单。

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

JavaScript 设计模式之策略模式

每天一点Linux --- 进入终端模式

策略模式的双胞胎:状态模式

行为型模式之策略模式

设计模式之策略模式

策略模式(C++)