行为型模式 —— 策略模式

1,090 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

什么是策略模式

策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。

策略模式定义和封装了一系列的算法,它们是可以相互替换的,也就是说它们具有共性,而它们的共性就体现在策略接口的行为上,另外为了达到最后一句话的目的,也就是说让算法独立于使用它的客户而独立变化,我们需要让客户端依赖于策略接口。

一种很简单的解释,在我们的开发过程中,经常会遇到大量的 if...else 或者 switch...case 语句,当这些语句在开发中只是为了起到分流作用,这些分流和业务逻辑无关,那么这个时候就可以考虑用策略模式

策略模式的结构

 

这个模式涉及到三个角色:

  • 上下文环境(Context)角色:持有一个Strategy的引用。

  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为

策略模式的应用场景

举一个例子,商场搞促销--打8折,满200送50,满1000送礼物,这种促销就是策略。

再举一个例子,dota里面的战术,玩命四保一,三伪核体系,推进体系,大招流体系等,这些战术都是一种策略。

应用场景:

1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。

2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。

3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。

策略模式的实现

Strategy类,定义所有支持的算法的公共接口

//Strategy类,定义所有支持的算法的公共接口
public abstract class Strategy {
    //算法方法
    public abstract void algorithmInterface();
}

ConcreteStrategy,封装了具体的算法或行为,继承于Strategy

//算法A
class ConcreteStrategyA extends Strategy {
    @Override
    public void algorithmInterface() {
        System.out.println("算法A的实现");
    }
}
//算法B
class ConcreteStrategyB extends Strategy{
    @Override
    public void algorithmInterface() {
        System.out.println("算法B的实现");
    }
}
//算法C
class ConcreteStrategyC extends Strategy {
    @Override
    public void algorithmInterface() {
        System.out.println("算法C的实现");
    }
}

Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用

//Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用
public class Context {
    private Strategy strategy;
    
    public context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    //上下文接口
    public void contextInterface() {
        strategy.algorithmInterface();
    }
}

客户端代码

public static void main(String[] args) {
    Context context;

    context = new Context(new ConcreteStrategyA());
    context.contextInterface();

    context = new Context(new ConcreteStrategyB());
    context.contextInterface();

    context = new Context(new ConcreteStrategyC());
    context.contextInterface();
}

策略模式和简单工厂模式的结合

改造后的Context

public class Context {
    private Strategy strategy = null;
    
    public Context(String type) {
        if ("A".equals(type)) {
            ConcreteStrategyA a = new ConcreteStrategyA();
            strategy = a;
        } else if ("B".equals(type)) {
            ConcreteStrategyB b = new ConcreteStrategyB();
            strategy = b;
        } else if ("C".equals(type)) {
            ConcreteStrategyC c = new ConcreteStrategyC();
            strategy = c;
        }
    }
    
    //上下文接口
    public void ContextInterface()
    {
        strategy.algorithmInterface();
    }
}

改造后的客户端代码

public static void main(String[] args) {
    Context context = new Context("A");
    context.contextInterface();
    
    Context context = new Context("B");
    context.contextInterface();
    
    Context context = new Context("C");
    context.contextInterface();
}

对比下改造前后的区别不难看出,改造前客户端需要认识两个类,Context和ConcreteStrategy。而策略模式和简单工厂模式结合后,客户端只需要认识一个类Context,降低了耦合性。

策略模式的优缺点

优点:

  • 1、结构清晰,把策略分离成一个个单独的类「替换了传统的 if else」
  • 2、代码耦合度降低,安全性提高「各个策略的细节被屏蔽」

缺点:

  • 1、客户端必须要知道所有的策略类,否则你不知道该使用那个策略,所以策略模式适用于提前知道所有策略的情况下
  • 2、策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)

总结

策略模式,实质就是封装了一些算法,让算法可以互相替换,用户可以自由选择这些算法进行操作。策略模式本身理解起来没什么难点,但是在实际应用中其本身主要结合工厂模式一起使用。