设计模式(一) 策略模式

一、模式动机

为什么要使用策略模式呢?在日常开发中,我们可以发现一种需求可以有不同的方法来实现,比如我们要对一个数组进行排序,就可以使用多种不同的排序方法(选择排序、冒泡排序、快速排序等),每一种排序方法都可以被称作一种策略,我们可以在不同的情况下来选择不同的策略进行排序。在实现的时候我们可能会写一个算法类,包含了所有的排序算法,接着在我们需要排序的类(简称客户端)中创建算法类的对象,然后写一大段if...else来选择对象类中不同的排序算法。这种实现方式比较容易想到,但如果我们要增加一种新的排序算法,那么需要修改两个类:算法类和客户端,扩展和维护起来非常麻烦。为了解决这个问题,我们可以将每一个排序算法封装在一个独立的类中,这样一个独立的类我们称之为一种策略,为了保证这些策略的一致性,我们要建立一个抽象策略类,让包含排序算法的具体策略类实现抽象策略类。

二、模式定义

策略模式定义了算法族,并将这些算法封装起来成为类,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

三、模式结构

策略模式涉及到3个角色:

1、Context:环境类(上下文类),持有一个Strategy的引用,负责调用相关算法;

2、Strategy:抽象策略类,通常由接口或抽象类实现;

3、ConcreteStrategy:具体策略类,实现了抽象策略类。

这3种角色的代码可以用以下方式实现:

抽象策略类Strategy:

public interface Strategy{
    /**
     * 策略中包含的算法
     */
    void algorithm();
}

具体策略类ConcreteStrategy:

具体策略类实现了抽象策略类:

public class ConcreteStrategyA implements Strategy{
    @Override
    public void algorithm(){
        //具体算法或行为
    }
}
public class ConcreteStrategyB implements Strategy{
    @Override
    public void algorithm(){
        //具体算法或行为
    }
}

环境类Context:

public class Context{
    //持有一个Strategy对象
    private Strategy strategy;

    //在构造函数中传入Strategy对象
    public Context(Strategy strategy){
        this.strategy = strategy;
    }

    //调用策略类中的算法
    public void contextInterface(){
        //if...else可以转移到这里
        strategy.algorithm();
    }

}

可以在客户端Client类中进行测试:

public class Client{
    public static void main(String[] args){
        ConcreteStrategyA csa = new ConcreteStrategyA();
        Context context = new Context(csa);
        context.contextInterface();
    }
}

可以看到,在环境类Context中持有一个抽象的Strategy对象,而不是某一个具体的策略类,这样利用多态特性,当有新的排序算法时,我们只需要实现Strategy接口,而不用去修改客户端,也就是针对接口编程,而不是针对实现编程。通过策略模式,算法的使用和算法的实现被分离开来。

四、优缺点

优点:

1、策略类易于扩展和维护;

2、使用策略模式可以避免使用多重条件转移语句

缺点:

1、客户端必须实现知道所有的策略类,并自行决定使用哪一个策略类;

2、在策略模式中将每一种算法都封装成一个策略类,这样会造成策略类过多,维护起来会带来额外开销。

五、适用场景

1、系统中的类主要逻辑相同,只是部分逻辑的实现方法不同,这样使用策略模式就可以动态的选择不同的行为;

2、需要安全地封装同一类型的操作。

posted @ 2018-04-18 19:49  ColdCode  阅读(319)  评论(0编辑  收藏  举报
AmazingCounters.com