Android 设计模式--策略模式

今天来看下策略模式

以下内容大部分来自《设计模式》一书,仅做了整理。

定义:策略模式定义了算法族,分别封装起来,让他们之间可以相互替换。


我们来设计一个场景:一个关于鸭子的游戏,鸭子在水里边游泳,边呱呱叫着。

超类:Duck.class

/**
 * 鸭子超类
 */
public abstract class Duck {

    /**
     * 鸭子会呱呱叫
     */
    public void qucak(){};

    /**
     * 鸭子会游泳
     */
    public void swim(){};

    /**
     * 鸭子的外观,子类的鸭子都要自己去实现自己的外观,所以display方法是抽象的
     */
    public abstract void display();

}
而鸭子的子类需要继承Duck类,就可以实现呱呱叫,和游泳能力,只需要自己实现自己的外观就可以了。

绿头鸭:MallardDuck.class

/**
 * 绿头鸭
 */
public class MallardDuck extends Duck{
    private static String TAG=MallardDuck.class.toString();
    @Override
    public void display() {
        Log.i(TAG,"----------这是绿头鸭---------");
    }
}
红头鸭:RedHeadDuck.class

/**
 * 红头鸭
 */
public class RedHeadDuck extends Duck {
    private static String TAG = RedHeadDuck.class.toString();

    @Override
    public void display() {
        Log.i(TAG, "----------这是红头鸭---------");
    }
}
如果现在需求有改动说是这些鸭子要会飞,我们只需要在超类里添加一个fly方法就可以了,而子类并不需要做改动

/**
 * 鸭子超类
 */
public abstract class Duck {

    /**
     * 鸭子会呱呱叫
     */
    public void qucak(){};

    /**
     * 鸭子会游泳
     */
    public void swim(){};

    /**
     * 鸭子的外观,子类的鸭子都要自己去实现自己的外观,所以display方法是抽象的
     */
    public abstract void display();
    /**
     * 飞行
     */
    public void fly(){};

}
然后产品经理跟你说我们需要向里面添加一种鸭子,叫橡皮鸭。现在问题就出现了,橡皮鸭是玩具,并不会飞,也不会呱呱叫。

橡皮鸭:RubberDuck.class

/**
 * 橡皮鸭
 */
public class RubberDuck extends Duck{
    private static String TAG = RubberDuck.class.toString();

    /**
     * 橡皮鸭并不会呱呱叫,所以重写父类呱呱叫方法
     */
    @Override
    public void qucak() {
        Log.i(TAG, "----------橡皮鸭不会呱呱叫---------");
    }

    @Override
    public void display() {
        Log.i(TAG, "----------这是橡皮鸭---------");
    }

    /**
     * 橡皮鸭也不会飞,重写父类飞行方法
     */
    @Override
    public void fly() {
        Log.i(TAG, "----------橡皮鸭不会飞---------");
    }
}
这样看似是一个可行的方案,可是鸭子的种类越来越多,鸭子会叫的、不会叫的、会游泳的、不会游泳的。。。。,也可能会增加一个鸭子属性,而已有的鸭子对这个属性又有不同的属性,我们就必须再去每一个鸭子子类里去重写父类的这个方法,这样一直在重写父类的方法,导致代码重复,工作量越来越大,这并不是我们想要看到的方案。

如果能有一种能够建立软件的方法,能够让我们对既有的代码影响最小的方式来改动软件,我们就可以花更少的时间重做代码,节省大量的工作量、工作时间那该多好。

不管一个软件设计的多好,一段时间后,需求总会做改动。

现在可以看出继承(extends)并不能很好的解决这个问题,因为你不知道在未来子类会新冒出一个什么属性。

所有我们将引出“针对接口编程”概念。

“针对接口编程”的真正意思是“针对超类型(supertype)编程”

这里所谓的“接口”有多个含义,接口是一个“概念”,也是一种Java的interface构造。你可以在不涉及Java interface的情况下,“针对接口编程”,关键就在多态。利用多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。“针对超类型编程”这句话,可以明确的说成“变量的声明类型应该是超类,通常是一个抽象类或者是一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。这也意味着,声明类时不用理会以后执行时的真正对象类型!”

---------------------------------------------------------------------下面才是正文------------------------------------------------------------------------------------------

上面这些话是书里说的,理解不了就别看了,简单的说就是把易变的部分做成接口(interface)形式,在父类里声明一个接口变量,在子类里给这个变量赋值。

下面上代码:

鸭子的呱呱叫和飞行行为是易变的,我们就把呱呱叫和飞行行为做成接口形式。

呱呱叫接口:QuackInterface.class

/**
 * 呱呱叫行为接口
 */
public interface QuackInterface {
    /**
     * 鸭子会呱呱叫
     */
    void qucak();
}
飞行行为接口:FlyInterface.class

/**
 * 飞行行为接口
 */
public interface FlyInterface {
    /**
     * 飞行
     */
    void fly();
}

以前的Duck.class重新写

/**
 * 鸭子超类
 */
public abstract class Duck {
    /**
     * 为行为接口声明两个引用变量
     */
    QuackInterface quackInterface;//呱呱叫行为接口
    FlyInterface flyInterface;//飞行行为接口

    /**
     * 鸭子会游泳
     */
    public void swim(){};

    /**
     * 鸭子的外观,子类的鸭子都要自己去实现自己的外观,所以display方法是抽象的
     */
    public abstract void display();

    /**
     *  呱呱叫行为委托给呱呱叫接口
     */
    public void perfromQuack(){
        quackInterface.qucak();
    }
    /**
     *  飞行行为委托给飞行接口
     */
    public void perfromFly(){
        flyInterface.fly();
    }

}
绿头鸭类重写:MallardDuck.class

/**
 * 绿头鸭
 */
public class MallardDuck extends Duck implements QuackInterface,FlyInterface{
    private static String TAG=MallardDuck.class.toString();
    @Override
    public void display() {
        Log.i(TAG,"----------这是绿头鸭---------");
    }

    @Override
    public void qucak() {
        Log.i(TAG,"----------绿头鸭呱呱叫---------");
    }
    @Override
    public void fly() {
        Log.i(TAG,"----------绿头鸭会飞---------");
    }
}
橡皮鸭:RubberDuck.class

/**
 * 橡皮鸭
 */
public class RubberDuck extends Duck implements QuackInterface,FlyInterface{
    private static String TAG = RubberDuck.class.toString();

    @Override
    public void display() {
        Log.i(TAG, "----------这是橡皮鸭---------");
    }

    @Override
    public void qucak() {
        Log.i(TAG, "----------橡皮鸭不会呱呱叫---------");
    }

    @Override
    public void fly() {
        Log.i(TAG, "----------橡皮鸭不会飞---------");
    }

}
我们创建这些类之后,就可以使用了

Duck duck=new MallardDuck();
duck.perfromQuack();
duck.perfromFly();
Duck duck=new RubberDuck();
duck.perfromQuack();
duck.perfromFly();
这样就可以创建出会飞、会呱呱叫的绿头鸭和不会飞、不会叫的橡皮鸭了。

-------------------------------------------------------------动态设定行为,下面的是更好的方案---------------------------------------------------------------------------------------------------

先拿一个飞行属性举例。

在Duck.class中加入一个方法:

public void setFlyInterface(FlyInterface flyInterface) {
    this.flyInterface = flyInterface;
}
完整Duck.class
/**
 * 鸭子超类
 */
public abstract class Duck {
    /**
     * 为行为接口声明引用变量
     */
    FlyInterface flyInterface;//飞行行为接口

    /**
     * 鸭子会游泳
     */
    public void swim(){};

    /**
     * 鸭子的外观,子类的鸭子都要自己去实现自己的外观,所以display方法是抽象的
     */
    public abstract void display();

    /**
     *  飞行行为委托给飞行接口
     */
    public void perfromFly(){
        flyInterface.fly();
    }


    public void setFlyInterface(FlyInterface flyInterface) {
        this.flyInterface = flyInterface;
    }
}
新增两个类

/**
 * 这个鸭子不会飞
 */
public class NoFlyClass implements FlyInterface{
    private static String TAG=NoFlyClass.class.toString();
    @Override
    public void fly() {
        Log.i(TAG, "----------我不会飞---------");
    }
}
/**
 * 这个鸭子会飞
 */
public class FlyClass implements FlyInterface{
    private static String TAG=FlyClass.class.toString();
    @Override
    public void fly() {
        Log.i(TAG, "----------我会飞---------");
    }
}
重写绿头鸭类:MallarDuck.class

/**
 * 绿头鸭
 */
public class MallardDuck extends Duck{
    private static String TAG=MallardDuck.class.toString();

    @Override
    public void display() {
        Log.i(TAG,"----------这是绿头鸭---------");
    }
}
重写橡皮鸭类:RubberDuck

/**
 * 橡皮鸭
 */
public class RubberDuck extends Duck{
    private static String TAG = RubberDuck.class.toString();

    @Override
    public void display() {
        Log.i(TAG, "----------这是橡皮鸭---------");
    }

}
使用的时候

Duck mallardDuck=new MallardDuck();
mallardDuck.setFlyInterface(new FlyClass());
mallardDuck.perfromFly();

Duck rubberDuck=new RubberDuck();
rubberDuck.setFlyInterface(new NoFlyClass());
rubberDuck.perfromFly();
这篇文章到这就结束了。

如有错误或纰漏的地方,欢迎指正。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值