Java设计模式之策略模式详解

花荣
• 阅读 1565
策略模式就是定义了一系列的的算法,将它们都单独封装起来,让他们之间可以相互替换,可以让算法的变化独立于使用算法的客户。

首先创建一个Dog父类,有run方法控制跑,jump方法控制跳,color方法控制颜色。

public class Dog {
    public void run(){
        System.out.println("狗在跑");
    }

    public void jump(){
        System.out.println("狗在跳");
    }

    public void color(){
    }
}

创建两个子类,分别是WhiteDog和BlackDog,都重写了父类的color方法,运行一下。

public class WhiteDog extends Dog {

    @Override
    public void color() {
        System.out.println("白颜色的狗");
    }
}

public class BlackDog extends Dog {

    @Override
    public void color() {
        System.out.println("黑颜色的狗");
    }
}

public class Test {
    public static void main(String[] args){
        WhiteDog whiteDog = new WhiteDog();
        whiteDog.run();
        whiteDog.jump();
        whiteDog.color();
        BlackDog blackDog = new BlackDog();
        blackDog.run();
        blackDog.jump();
        blackDog.color();
    }
}

结果:
狗在跑
狗在跳
白颜色的狗
狗在跑
狗在跳
黑颜色的狗


这个时候看上去好像很完美没有任何问题,但是有一天我们又新建了一个公仔狗的对象Doll dog,这个时候我们发现好像有点不对,公仔狗是不会跳也不会跑的。可以如果继承了Dog父类他就自带跑和跳的功能了,那就不对了。

public class DollDog extends Dog {

    @Override
    public void color() {
        System.out.println("五颜六色");
    }
}

DollDog dollDog = new DollDog();
dollDog.run();
dollDog.jump();
dollDog.color();

结果:
狗在跑
狗在跳
五颜六色的玩具狗


这个时候我们灵机一动想到可以让子类覆盖父类run方法和jump方法,让DollDog中的跑和跳功能失效,我们再运行一下。

@Override
public void run() {
    System.out.println("玩具狗不会跑");
}

@Override
public void jump() {
    System.out.println("玩具狗不会跳");
}

结果:
玩具狗不会跑
玩具狗不会跳
五颜六色的玩具狗


看起来是解决了问题,但是如果一天要增加100个各种各样的狗的话难道我们要让100个新建的子类都重写父类的方法吗?这个时候父类里面还只有3个方法,如果是30个呢?如果我们都靠子类重写的话那效率该多低呢?有没有别的方法来解决呢?答案是肯定的。下面我们就来介绍怎么用策略模式来解决这个问题。
首先我们要知道设计模式中第一个原则,要把代码中经常需要修改的部分独立抽取出来,不要和其他代码混在一起,这样更便于我们扩展要修改的部分 。目前来看最常变化的是run和jump方法。所以我们可以将这两个方法抽取出来,这里就要说到设计模式中第二个原则,针对接口编程,而不是现实编程。比如run和jump有不同的种类,我们可以声明一个接口里面定义run和jump方法,然后创建许多类去实现,调用的时候动态选择类型。这种类被称为行为类。行为类中的代码可以进行复用,却不会有继承带来的那些麻烦。

定义方法的接口:

public interface RunBehavior {
    void run();
}

public interface JumpBehavior {
    void jump();
}

实现方法的行为类:

public class RunNoWay implements RunBehavior {
    @Override
    public void run() {
        System.out.println("不会跑");
    }
}

public class RunFast implements RunBehavior {
    @Override
    public void run() {
        System.out.println("很快的跑");
    }
}

public class RunSlow implements RunBehavior {
    @Override
    public void run() {
        System.out.println("很慢的跑");
    }
}

public class JumpNoWay implements JumpBehavior {
    @Override
    public void jump() {
        System.out.println("不会跳");
    }
}

public class JumpFast implements JumpBehavior {
    @Override
    public void jump() {
        System.out.println("很快的跳");
    }
}

现在我们将变化的部分抽取出来了,所以Dog父类就会把run和jump的操作委托给行为类处理,那么具体要怎么使用这些行为类?这里就需要在Dog父类中定义两个实例变量,声明类型为RunBehavior和JumpBehavior,所以在代码运行的时候会用多态的方式引用正确的类型。然后在父类中的run和jump方法中委托行为类去执行功能。

public class Dog {
    public RunBehavior runBehavior;
    public JumpBehavior jumpBehavior;

    public void run(){
        runBehavior.run();
    }

    public void jump(){
        jumpBehavior.jump();
    }

    public void color(){
    }
}

最后当我们没出现一个新的类型的狗狗的时候,我们为它创建一个新类然后继承Dog父类,然后我们在子类的构造方法中获取父类中两个接口的引用,根据自己的需要通过多态指定不同的行为类。

public class SuperDog extends Dog {

    public SuperDog(){
        runBehavior = new RunFast();
        jumpBehavior = new JumpFast();
    }

    @Override
    public void color() {
        System.out.println("红蓝相间的超人狗");
    }
}

Dog dog = new SuperDog();
dog.jump();
dog.run();
dog.color();

结果:
很快的跳
很快的跑
红蓝相间的超人狗


最后我们还有一个小问题,每次指定选择类的时候都是在子类的构造方法中指定,可不可以动态的指定呢?当然可以,我们只需要为声明的接口引用添加两个set方法。然后在外部调用即可。

public void setRunBehavior(RunBehavior runBehavior) {
    this.runBehavior = runBehavior;
}

public void setJumpBehavior(JumpBehavior jumpBehavior) {
    this.jumpBehavior = jumpBehavior;
}

Dog dog = new SuperDog();
dog.jump();
dog.run();
dog.color();

dog.setJumpBehavior(new JumpNoWay());
dog.setRunBehavior(new RunNoWay());
dog.jump();
dog.run();
dog.color();

结果:
很快的跳
很快的跑
红蓝相间的超人狗
不会跳
不会跑
红蓝相间的超人狗


总结:
策略模式就是把所有的可变的行为都抽取出来放到接口中,然后定义很多的行为类去实现接口。在父类中声明了接口的引用利用多态去动态的选择自己需要的行为类,避免了以前因为单纯的继承造成的每次的新变动都需要写大量的重复代码,而现在只需要定义好行为类进行复用即可,不需要修改原本的代码。

点赞
收藏
评论区
推荐文章
Easter79 Easter79
4年前
Vue 骚技巧,策略模式实现动态表单验证
!(https://oscimg.oschina.net/oscnet/5e0568a314054f2d995c1562bda18f70.png)策略模式(StrategyPattern)又称政策模式,其定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。
红橙Darren 红橙Darren
4年前
Android模板设计模式之 - 构建整个应用的BaseActivity
1\.模式介绍模式的定义定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。所有分享大纲:视频讲解地址:模式的使用场景1.多个子类有公有的方法,并且逻辑基本相同时。2.重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。3.重构时,模板方法模式
Wesley13 Wesley13
4年前
Java设计模式
一、策略模式(让算法与对象独立)    策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。!(http://static.oschina.net/uploads/space/2016/1108/180244_oYm8_1789589.png)二、观察者模式(让你的对象知悉现状) 
Wesley13 Wesley13
4年前
PHP设计模式之模板方法模式
PHP设计模式之模板方法模式模板方法模式,也是我们经常会在不经意间有会用到的模式之一。这个模式是对继承的最好诠释。当子类中有重复的动作时,将他们提取出来,放在父类中进行统一的处理,这就是模板方法模式的最简单通俗的解释。就像我们平时做项目,每次的项目流程实都差不多,都有调研、开发、测试、部署上线等流程。而具体到每个项目中,这些
Wesley13 Wesley13
4年前
Java 设计模式系列(十二)策略模式(Strategy)
Java设计模式系列(十二)策略模式(Strategy)策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。一、策略模式的结构策略模式是对算
Wesley13 Wesley13
4年前
23种设计模式(6):模版方法模式
定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。类型:行为类模式类图:!(http://static.oschina.net/uploads/img/201603/22162800_BFc1.jpg)       事实上,模版方法是编程中一个
Wesley13 Wesley13
4年前
23种设计模式(面向对象语言)
一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。创建型模式是用来创建对象的模式,抽象了实例化的过程,帮助一个系统独立于其他关联对象的创建、组合和表示方式。所有的创建型模式都有两个主要功能:  1.将系统所使用的具体类的信息封装起来  2.隐藏
Wesley13 Wesley13
4年前
Java 设计模式系列(十三)模板方法
Java设计模式系列(十三)模板方法模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。一、模板方法的结构
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际
京东云开发者 京东云开发者
10个月前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际
京东云开发者 京东云开发者
8个月前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际