Java基础再回首之设计模式系列①-----StrategyPattern 策略者模式(案列教程,附带demo)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://xuhong.blog.csdn.net/article/details/71747282

一、前言

自己学java学的也熟悉了。踏入工作的不归路之后,身为一个Android开发工程师,不仅要Java基础扎实,还要对其的设计模式有所掌握,最近在群听到《Head First》这本书的设计模式很好,也很适合我现在的情况,所以决定全心全意学好Java的设计模式。于是,在此写一系列设计模式的博文,如有兴趣请借鉴。


我的座右铭: 成功的反义词不是失败,而是什么都不去做。

希望这句话同样的激励着正在读大学或者已经工作的你和我。共勉,哈哈~


二、案列。

现在你要为某公司的游戏设计一类武器,客户要求要有斧头、剑、火炮,目前就三种武器。

要求一:每种武器一定要有其的使用方法、外表特点、攻击特效。

要求二:某些武器有使用权限,比如只能限定RMB玩家,而不允许非RMB玩家使用。


2.1 普通方案:

  1. 把武器设计为超类,在其里面把必须有的方法设计为抽象方法:使用方法、外表特点、攻击特效。这样就可以让子类来实现了其具体的内容了。
  2. 使用权限问题的就让不同的子类做不同的处理,没有权限的就覆盖不做任何事情,而拥有权限的武器子类就可以做自己的事情。

这方案看起来,好像很有成就感咯。哈哈~

于是乎,我们就有了下面的思维导图:


这里写图片描述

于是乎,就有了以下代码:

Weapon.class 父类

package Weapon;/*
 * 项目名:StrategyPattern-Sample
 * 文件名:Weapon
 * 创建时间:2017/5/12下午 2:46
 * 创建者 xuhong
 * 描述:武器 ,父类
 */

public abstract class Weapon {

    // 抽象方法:显示武器样式
    public abstract void display();

    //抽象方法:显示特效
    public abstract void specialEffects();

    //抽象方法:使用方法
    public abstract void usage();

    //抽象方法: 使用权限
    public abstract void peimission();
}

axe.class 斧头子类

package Weapon;

/*
 * 项目名:StrategyPattern-Sample
 * 包名:Weapon
 * 文件名:Axe
 * 创建时间:2017/5/12  下午 2:50
 * 创建者 xuhong
 * 描述:斧头子类
 */

public class Axe extends Weapon {

    @Override
    public void display() {
        System.out.print("斧头样式。");
    }

    @Override
    public void specialEffects() {
        System.out.print("斧头特效。");
    }

    @Override
    public void usage() {
        System.out.print("斧头的使用方法。");
    }

    @Override
    public void peimission() {
        System.out.print("斧头不需要RMB购买。");
    }
}

使用:

import Weapon.Axe;

public class Main {

    public static void main(String[] args) {
        Axe axe = new Axe();
        axe.display();
        axe.specialEffects();
        axe.usage();
        axe.peimission();
    }
}

输出如下:
这里写图片描述


至今到此,哇!好像好简单的样子,得到老板的赏心悦目。加工资~So happy~


过了一个月,客户又有了新的要求:要求新增多种武器,但是这几种武器很特别,在使用这些武器有不同的金币加成。 解决方法:我们又在父类写了几个抽象方法,把之前的几个子类覆盖这方法而不做任何事情。


又过了几个月,又新增几种武器,但是这几种武器使用不能提供加金币…. 后期维护代码我们发现很麻烦,每次都要在父类加抽象方法,而且还有在每个子类覆盖。


问题来了:
1.前面仅仅新增几种武器的话,还可以接受。但是后期,稍微一新增某种特别的属性,会牵一发动全身,造成其他子类武器不想要的改变。
2.代码在多个子类重复。而且覆盖没有使用。
3.很难知道某种武器的全部属性,因为某些属性只是覆盖什么事情都没有做。
4.运行代码时候,不容易动态改变武器的属性。

策略者模式来了:


分开变化和不变化的部分:

从哪里开始呢?就我们目前所知,除了display()、usage()、specialEffects()方法之外,permission()方法这类方法经常改变。
现在为了要分开“变化与不变化的部分”,我们准备建立两组类(完全远离 Weapon),一个是与权限permission() 相关的,一个是与 金币加成的 goldAdd() 相关的,每一组将实现各自的动作。比如说,这种武器加成每次加100金币,这种每次加200金币,还有一种加300金币。


设计武器的金币加成为例:

我们所希望一切具有弹性。毕竟,正是因为一开始武器的各种属性没有弹性,才让我们走上这条道路。比如,我们设计一种武器实例,希望指定的每次使用加成100金币的属性给予他。而且我们在使用时候,可以在某些条件不给予它这个属性。这样就可以动态的为这个武器设计属性了。


于是乎,我们利用接口代表每个属性,比方说:permission和goldAdd,而具体的使用权限和金币加成多少都用一个类来实现这个接口,在这个类的重写方法具体的做自己的事情。这些类就叫“属性类”。由属性类而不是Weapon类来实现属性接口。


这样的做法迥异于以往,之前的做法是:属性由子类类来实现,这种做法都是依赖于“实现”,我们被绑得死死的,很难动态改变其属性。


三、代码分析。


3.1、我们先看工程架构:

这里写图片描述


3.2、父类 WeaponSuper.class:


分析:
1.首先在全局变量声明为public的2个接口(不加public默认就是当前类的访问权限),其作用是交给子类去实例化该接口对象,子类需要什么属性,让他们自己选择,这样就不用在父类操作子类的事情,也不必关心子类去做了什么,重要的是子类可以自由选择组合。
2.上面说到变与不变,这里不变的属性方法我们提取出来,在父类里面写成抽象方法,让子类去做自己的事情。那些易变化的属性我们改为接口,用组合去实现,并不是用继承。

package Weapon;/*
 * 项目名:StrategyPattern-Sample
 * 包名:WeaponSuper
 * 文件名:WeaponSuper
 * 创建时间:2017/5/12下午 2:46
 * 创建者 xuhong
 * 描述:武器 ,父类
 */

import Interface_WeaponProperty.IGoldAdd;
import Interface_WeaponProperty.IPermission;

public abstract class WeaponSuper {

     IGoldAdd iGoldAdd;
     IPermission iPermission;

    //显示武器的加成
    public void showGoldAdd(){
        int goldAdd = iGoldAdd.GoldAdd();
        System.out.print("这武器新增"+goldAdd+"金币哦!");
    }

    //显示武器的权限
    public void showPeimission(){
        iPermission.permission();
    }

    /**
     * 设置武器加成的方法
     * @param iGoldAdd 接口
     */
    public void setiGoldAdd(IGoldAdd iGoldAdd){
        this.iGoldAdd=iGoldAdd;
    }

    // 抽象方法:显示武器样式
    public abstract void display();

    //抽象方法:显示特效
    public abstract void showSpecialEffects();

    //抽象方法:使用方法
    public abstract void showUsage();

}

3.3、接口与其实现类分析。


3.3.1 .金币加成的接口 IGoldAdd 。这里的代码就没什么好分析了,就一个抽象方法。

package Interface_WeaponProperty;

public interface IGoldAdd {
     int GoldAdd();
}

3.3.2 权限使用的接口 Interface_WeaponProperty

package Interface_WeaponProperty;

public interface IPermission {
     void permission();
}

3.3.3 .重头戏来了,看看我们实现类的代码。这是我们自由想要做的事情,比如我写了三个实现类,分别做了加300、200、100金币的加成,后续你也可以添加一些不同金币加成类。

import Interface_WeaponProperty.IGoldAdd;

//增加300金币
public class GoldAdd_300 implements IGoldAdd {
    @Override
    public int GoldAdd() {
        return 300;
    }
}

import Interface_WeaponProperty.IGoldAdd;

//增加200金币
public class GoldAdd_200 implements IGoldAdd{
    @Override
    public int GoldAdd() {
        return 200;
    }
}

import Interface_WeaponProperty.IGoldAdd;

//增加100金币
public class GoldAdd_100 implements IGoldAdd {
    @Override
    public int GoldAdd() {
        return 100;
    }
}

3.3.4 相信你看到了上面的实现类,你也知道权限接口的实现类怎么写了吧、无非也是写不同的类做不同方法。好吧。直接撸代码。


import Interface_WeaponProperty.IPermission;

public class NeedPermission implements IPermission {
    @Override
    public void permission() {
        System.out.print("需要权限的武器!");
    }
}
import Interface_WeaponProperty.IPermission;

public class NoNeedPermission implements IPermission {
    @Override
    public void permission() {
        System.out.print("不需要权限的武器!");
    }
}

4.核心代码来了,看看我们的子类该怎么做?


分析:我们这里写了一个子类,在构造方法实例化父类声明的对象。而且不变共有的属性,我们都继承了并且做自己的事情。

import GoldAdd.GoldAdd_100;
import Permission.NoNeedPermission;

public class Axe extends WeaponSuper {

    //父类声明的对象在子类的构造方法实例化
    public Axe() {
        iGoldAdd = new GoldAdd_100();
        iPermission = new NoNeedPermission();
    }
    @Override
    public void display() {
        System.out.print("我只是一个斧头!");
    }

    @Override
    public void showSpecialEffects() {
        System.out.print("斧头没有特效");
    }

    @Override
    public void showUsage() {
        System.out.print("斧头的使用说明!");
    }  
}

5. 看看我们怎么组合,怎么使用。


分析:

1.这里我只是声明一个父类的对象,去new一个子类,当然了。你也可以去声明对象为自己,有何不同?声明为父类对象去实例化子类时候,该对象只能调用被继承下来的方法,不能调用子类的其他的方法。
现在我们可以动态的在代码改变武器的某些属性了,下面代码我改为了300金币的加成呢。

2.你还可以去子类里面不用实例化某个接口对象,这里你就随心所欲的想要自己的属性了,跟父类很大的脱离关系。


import GoldAdd.GoldAdd_300;
import Weapon.Axe;
import Weapon.WeaponSuper;

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

      WeaponSuper axe = new Axe();
      axe.showGoldAdd();
      axe.display();
      axe.showPeimission();
      axe.showUsage();

      //动态的给予这个武器300金币的加成
      axe.setiGoldAdd(new GoldAdd_300());
      axe.showGoldAdd();
    }
}

四、归纳。


1.设计原则:针对接口编程,而不是针对实现的编程。

2.设计原则:找到应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。

3.多用组合,少用继承。

4.主要是用来分离算法,在相同的行为抽象下有不同的具体实现策略。这个模式很好的演示了开闭原则:定义抽象,增加新的策略只需要增加新的类,然后在运行中动态更换即可,没有影响到原来的逻辑,从而达到了很好的可扩展性。

5.在Android中使用策略者模式的多之又多,典型的是动画类Animation ,其父类里定义 Interpolator 插值器对象,用来在执行动画的时候达到所需要的速度变化效果。这样就也可在代码中动态的更新不同的动画效果了。这和我们上面的思想一样。


转载请注明原创:http://blog.csdn.net/xh870189248/article/details/71747282


源码:http://download.csdn.net/detail/xh870189248/9840941

展开阅读全文

没有更多推荐了,返回首页