设计模式——策略模式

简介: 1.策略模式定义一系列算法,把他们独立封装起来,并且这些算法之间可以相互替换。策略模式主要是管理一堆有共性的算法,策略模式让算法独立于使用它的客户而变化,客户端可以根据需要,很快切换这些算法,并且保持可扩展性。
1.策略模式
定义一系列算法,把他们独立封装起来,并且这些算法之间可以相互替换。策略模式主要是管理一堆有共性的算法,策略模式让算法独立于使用它的客户而变化,客户端可以根据需要,很快切换这些算法,并且保持可扩展性。
策略模式的本质:分离算法,选择实现。
2.UML类图

策略模式结构中包括三种角色:
  • 策略(Strategy):策略是一个接口,该接口定义若干个算法标识,即定义了若干个抽象方法。
  • 具体策略(ConcreteStrategy):具体策略是实现策略接口的类,具体策略实现策略接口所定义的抽象方法,即给出算法标识的具体算法。
  • 上下文(Context):上下文是依赖于策略接口的类,即上下文包含有策略声明的变量。上下文中提供一个方法,该方法委托策略变量调用具体策略所实现的策略接口中的方法。
3.举例说明
就拿程序员举例吧,假如现在我要写一个程序,我们可以使用java、php。那到底使用哪种语言呢?使用我们的简单工厂模式完全可以解决这个问题
1、抽象语言类
public interface CodeLanguage {
    void useLanguage();
}
2、具体语言类
public class CodeJava implements CodeLanguage {
    @Override
    public void useLanguage() {
        System.out.println("使用Java语言编程");
    }
}
public class CodePhp implements CodeLanguage {
    @Override
    public void useLanguage() {
        System.out.println("使用Php语言编程");
    }
}
3、工厂类
public class LanguageFactory {
    public static CodeLanguage getLanguage(String type){
        CodeLanguage codeLanguage=null;
        switch (type){
            case "java":
                codeLanguage=new CodeJava();
                break;
            case "php":
                codeLanguage=new CodePhp();
                break;
        }
        return codeLanguage;
    }
}
虽然问题解决了,但正如我们所说的简单工厂模式的缺点一样:
  • 工厂类负责所有对象的创建逻辑,该类出问题整个系统无法运行。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂方法。
  • 由于使用了静态工厂方法,所以工厂角色无法形成基于继承的等级结构。

    假如我们又要增加使用python语言,那么我们除了增加相应的语言类,还要修改工厂类,很明显这不是最佳的方法,而策略模式便是最好的选择。根据策略模式的定义,策略模式主要是管理一堆有共性的算法,这些算法封装到一个个的具体算法类中,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,根据“里氏代换原则”和面向对象的多态性,客户端可以选择使用任何一个具体算法类,并只需要维持一个数据类型是抽象算法类的对象。对比简单工厂模式,我们发现,简单工厂模式是利用工厂类根据参数来动态的生成具体产品类,然后单独的调用具体产品类的方法;而策略模式是由客户端创建这些具体算法类,然后交由上下文来调用这些具体算法类中的方法。
策略类接口
public interface CodeLanguage {
    void useLanguage();
}
具体策略类
public class CodeJava implements CodeLanguage {
    @Override
    public void useLanguage() {
        System.out.println("使用Java语言编程");
    }
}
public class CodePhp implements CodeLanguage {
    @Override
    public void useLanguage() {
        System.out.println("使用Php语言编程");
    }
}
这点和简单工厂模式是抽象产品和具体产品代码是一样的,下面是不同点,实现一个上下文对象
public class CodeContext {
    CodeLanguage codeLanguage;

    public CodeContext1(CodeLanguage codeLanguage) {
        this.codeLanguage = codeLanguage;
    }

    void useLanguage(){
        codeLanguage.useLanguage();
    }
}
使用模式
public class Application {
    public static void main(String[] args) {
        CodeContext context;
        context = new CodeContext(new CodeJava());
        context.useLanguage();
        context = new CodeContext(new CodePhp());
        context.useLanguage();
    }
}
上面是一个最简单的策略模式的实现方式,按照功能分为3个部分,定义策略抽象接口,然后根据具体算法实现策略接口,最后需要定义一个上下文对象。这里的上下文对象主要用来切换算法,上下文对象里面也是针对接口编程,具体算法实现被封装了。
4.策略模式的理解
上面实现的只是一种最简单的策略模式的框架,实际应用的时候,我们可以针对不同情况修改上下文对象和具体的算法实现。比如说,可以增加一个抽象类实现作为算法模板。抽象类里面我们可以封装一些公共的方法。这样实现具体的算法的时候,每个算法公共部分就被分离出来。
策略模式的目的是把具体的算法抽离出来,把每个算法独立出来。形成一系列有共同作用的算法组,然后这个算法组里面的算法可以根据实际情况进行相互替换。
策略模式的中心不是如何实现这些算法,而是如何组织和调用这些算法。也就是把我们平时写到一块的算法解耦出来,独立成一个模块,增强程序的扩展性。
策略模式里面的算法通常需要数据执行,我们可以根据实际情况把数据放在不同地方。例如可以放在上下文类里面,然后每个算法都可以使用这些数据。或者对接口封装一个抽象类,在抽象类里面添加数据。这些可以根据实际的情况综合考虑。设计模式里面没有一成不变的万能模式,每种模式都有变化版本,需要根据实际的项目进行变通。
5.策略模式优缺点
策略模式的优点:
策略模式完全符合“开放-封闭原则”。
策略模式提供了管理相关算法族的办法。恰当使用继承可以把公共的代码移到抽象策略类中,从而避免重复的代码。
策略模式提供了一种可以替换继承关系的办法。如果不使用策略模式,那么使用算法的环境类就可能会有一些子类,每一个子类提供一种不同的算法。但是,这样一来算法的使用就和算法本身混在一起,不符合“单一职责原则”,而且使用继承无法实现算法或行为在程序运行时的动态切换。
使用策略模式可以避免多重条件选择语句。
更好的扩展性:在策略模式中扩展新的策略实现非常容易,只要增加新的策略实现类,然后在选择使用策略的地方选择使用这个新的策略实现就好了。
策略模式缺点:
客户端必须知道所有的策略类,并自行决定使用哪一个策略类,而且这样也暴露了策略的具体实现。
由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会相应增多。
策略模式将造成系统产生很多具体策略类,任何细小的变化都将导致系统要增加一个新的具体策略类。
策略模式的一系列算法地位是平等的,是可以相互替换的,事实上构成了一个扁平的算法结构,也就是在一个策略接口下,有多个平等的策略算法,就相当于兄弟算法。而且在运行时刻只有一个算法被使用,这就限制了算法使用的层级,使用的时候不能嵌套使用。
6.模式优化
考虑到策略模式在使用的时候会过多的暴露策略类,代码的耦合性过高,结合简单工厂模式进行优化,对上下文类进行修改
public class CodeContext {
    CodeLanguage codeLanguage;

    public CodeContext(String type) {
        switch (type){
            case "java":
                CodeJava codeJava=new CodeJava();
                codeLanguage=codeJava;
                break;
                case "php":
                CodePhp codePhp=new CodePhp();
                codeLanguage=codePhp;
                break;
        }
    }

    void useLanguage(){
        codeLanguage.useLanguage();
    }
}
使用模式
CodeContext context = new CodeContext("java");
context.useLanguage();
context = new CodeContext("php");
context.useLanguage();
相比传统策略模式,我们把直接创建具体上下文对象改通过参数判断来生成,这样暴露给客户端的只有上下文对象,代码的耦合度更低,可以说这既是简单工厂模式的升级,也是策略模式的升级。

参考:


相关文章
|
1月前
|
设计模式 算法 PHP
php设计模式--策略模式(六)
php设计模式--策略模式(六)
11 0
|
4月前
|
设计模式 算法 搜索推荐
设计模式之策略模式
设计模式之策略模式
42 0
|
4月前
|
设计模式 算法 Java
行为型设计模式-策略模式(Strategy Pattern)
行为型设计模式-策略模式(Strategy Pattern)
|
14天前
|
设计模式 算法 Java
Java 设计模式:探索策略模式的概念和实战应用
【4月更文挑战第27天】策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在 Java 中,策略模式通过定义一系列的算法,并将每一个算法封装起来,并使它们可以互换,这样算法的变化不会影响到使用算法的客户。
21 1
|
4月前
|
设计模式 算法 Java
【设计模式】策略模式在数据接收和发送场景的应用
在数据接收和发送场景打算使用了if else进行判断。ASystem.sync("向A同步数据");BSystem.sync("向B同步数据");...非常麻烦,需求多了很臃肿!策略模式(Strategy Pattern)定义了一组同类型的算法,在不同的类中封装起来,每种算法可以根据当前场景相互替换,从而使算法的变化独立于使用它们的客户端(即算法的调用者)。// 创建两个策略对象// 创建上下文对象,并传入策略对象。
61 1
|
5月前
|
设计模式 算法
设计模式思考,简单工厂模式和策略模式的区别?
设计模式思考,简单工厂模式和策略模式的区别?
|
5月前
|
设计模式 Java
细说一下设计模式中的策略模式!
细说一下设计模式中的策略模式!
31 0
|
1月前
|
设计模式 算法 搜索推荐
23种设计模式,策略模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】设计模式是软件工程中的一种最佳实践指导,用于解决常见的设计问题。它们被分类为创建型、结构型和行为型模式。其中,策略模式是一种行为型设计模式,旨在定义一系列算法,封装每一个算法,并使它们可互换。策略模式允许算法独立于使用它们的客户端变化
22 1
|
2月前
|
设计模式 算法
策略模式--设计模式
策略模式--设计模式
17 0
|
2月前
|
设计模式 算法 Java
【设计模式】策略模式
【设计模式】策略模式