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

来源:互联网 发布:鲁大师linux版 编辑:程序博客网 时间:2024/05/22 08:09

一、前言

自己学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

1 0
原创粉丝点击