Java设计模式——策略模式

本文介绍策略模式的概念及其在软件设计中的应用。策略模式通过定义算法族并封装起来,使得算法可以在运行时动态替换,增强了系统的灵活性。文章通过示例展示了如何使用策略模式实现可插拔式的算法更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是策略模式

策略模式定义了算法族,并将其封装起来,让它们之间可以动态的替换,此模式让算法的变化独立于使用算法的客户。
策略模式是将算法实现与主体分离,这样主体可以动态的选择具体的算法实现。

策略模式举例

策略模式,是用类实现算法,以组合的形式组织到主体上。
比如我们有一个抽象主体,具有一个方法actionA()。此方法的实现可能会存在变化,而且我们希望这个actionA()的实现由额外的算法类来提供。首先我们定义这个抽象主体类AbstractMainObject,如下:

public interface AbstractMainObject {

    void actionA();
}

考虑到actionA()方法的具体实现可能有多种,我们可以通过用一个额外的类ActionA专门来提供A方法的实现,然后将这个实现类ActionA以组合的形式组织在AbstractMainObject的实现类AMainObject中。在我们的场景中,ActionA的实现在AMainObject类创建时会初始化,但是使用期间仍然存在变化,所以我们用更灵活的组合来实现。如下:

public class AMainObject implements AbstractMainObject {

    private ActionA actionA;

    public AMainObject() {
        actionA = new ActionAReal();
    }

    public void actionA() {
        actionA.actionA();
    }
}

上述AMainObject类的设计思想是,此实现类跟actionA()方法的一种实现算法是绑定的,所以在构造函数中直接使用了一个固定的实现方法。如果此类在构造时仍有可能会使用不同的算法,此时我们可以提供一个带有ActionA参数的构造方法,这样在实例化不同的AMainObject对象时,可以传入不同的ActionA实现。
为了应对ActionA的可变性,我们设计一个接口,这个接口只有一个抽象方法,来专门作为这个A方法的抽象父类方法,为我们后面的动态替换ActionA的实现类留下操作空间,这样的设计在修改实现方法时主体类不需要做代码的修改,系统更有弹性,也是『针对接口编程,而不是针对实现编程』原则的一种体现。如下:

public interface ActionA {

    void actionA();
}

这样我们在设计AbstractMainObject的实现类时可以根据具体情况使用不同的ActionA的实现类,比如就用ActionAReal类来实现ActionA类,如下:

public class ActionAReal implements ActionA {

    public void actionA() {
        System.out.println("ActionAReal");
    }
}

对于AMainObject,我们可以做到对ActionA方法『可插拔式、可替换式』的更新。比如我们用了一会ActionAReal后希望可以换另一个算法ActionAAnotherReal,其如下:

public class ActionAAnotherReal implements ActionA {

    public void actionA() {
        System.out.println("ActionAAnotherReal");
    }
}

而AMainObject要实现这种动态替换,只需要提供一个更换组合字段actionA的实现的方法即可。如下的useActionA():

public class AMainObject implements AbstractMainObject {

    private ActionA actionA;

    public AMainObject() {
        actionA = new ActionAReal();
    }

    public void actionA() {
        actionA.actionA();
    }

    public void useActionA(ActionA actionA) {
        this.actionA = actionA;
    }
}

现在我们可以创建一个测试类来演示策略算法的使用和动态替换,如下,其中void useActionA(ActionA actionA)方法在接口类AbstractMainObject中声明。

class MainObjectTest {
    public static void main(String[] args){

        AbstractMainObject  mainObject = new AMainObject();
        mainObject.actionA();

        mainObject.useActionA(new ActionAAnotherReal());
        mainObject.actionA();
    }
}

输出项为

ActionAReal
ActionAAnotherReal

关于策略模式的总结

策略模式最重要的特点是,可以动态的选择不同的算法来实现所声明的功能。对比一下如果选择传统的父类子类方式,每个子类都要选择实现或者不实现这个接口,这样难免硬编码到系统中,导致算法改变时,需要随之改动的东西很多,改动成本高,易出错。

此外这种设计模式将变化与不变充分分离,不变的部分是主体声明的此功能,而变化的地方是此功能的具体实现方法可能随着主体的实现类不同而改变,也可能在主体实现类的运行时发生变化。不变的部分定义在主体上,和算法的实现类上。变化的部分会在客户端代码上,由客户端来控制什么时候用什么算法。

可以看出策略模式关注的是对算法的封装,动态配置和使用。也就是不关心算法的具体实现,而是关心如何组织、配置这些算法,从而让程序更具有弹性。

策略模式也体现了一个设计原则:针对接口编程,而不是针对实现编程。这里的接口是指『父类』或者是『抽象类型』。类之间的交互时忽略对方的具体实现,依赖父类进行交互,这样再新增实现类时,调用方不需要修改代码,实现了解耦。

策略模式的缺点
1,客户端必须理解不同算法实现的区别,并知道何时使用什么算法,这在一定程度上造成客户端与策略算法服务端存在耦合。
2,用类来表示算法,如果算法很多的话,实现类的数目、对象的数目会很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值