首先看下策略模式官方一点的定义:定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
看了这个定义是否感觉一头雾水,我们以例子来解释:
现在我们有个系统需要用到一个鸭子类,鸭子有很多种,比如说玩具鸭,或者像天鹅的鸭子,这些不同种类的鸭子有一些共同的属性,比如飞翔,或者发出声音。不同种类的鸭子的属性的实现不同,就像正常鸭子不会飞,但某些变异的鸭子就会飞一样;又比如说一些玩具鸭能借助火箭飞翔,这可不是一般鸭子能做到的。
想属性这些经常变化的代码,可以将其抽出,形成一种动态的策略。
实现上面的一些需求,就可以用到策略模式了,给不同的鸭子装配不同的技能,并让这些技能可以随时装配。废话不多说,上代码:
首先我们要把各种属性(能力)抽象出来:
飞翔:
package duck.beh.impl;
/**
* 帮助鸭子实现飞的动作
* @author volador
*
*/
public interface FlyBehavior {
public void fly();
}
叫唤:
package duck.beh.impl;
/**
* 帮助鸭子实现呱呱叫动作
* @author volador
*
*/
public interface QuackBehavior {
public void quack();
}
然后需要设计一个超类(让每个鸭子都能拥有这些属性),给每个鸭子装配上这些属性:
package duck.abs;
import duck.beh.impl.FlyBehavior;
import duck.beh.impl.QuackBehavior;
/**
* 这是个抽象的鸭子
* @author volador
*
*/
public abstract class Duck {
//它具有两种能力,针对接口编程
protected FlyBehavior flyBehavior;
protected QuackBehavior quackBehavior;
public Duck(){}
//~~~~~~~~~~~~ 这些能力也是可以动态改变的(getter && setter) ~~~~~~~~~~~~~~~~~
public FlyBehavior getFlyBehavior() {
return flyBehavior;
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public QuackBehavior getQuackBehavior() {
return quackBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 关于鸭子的说明
*/
public abstract void diaplay();
/**
* 所有鸭子都会游泳
*/
public void swin(){
System.out.println("所有鸭子都能有游泳");
}
/**
* 委托飞行的动作
*/
public void performFly(){
this.flyBehavior.fly();
}
/**
* 委托呱呱叫的动作
*/
public void performQuack(){
this.quackBehavior.quack();
}
}
这样,关于鸭子的飞行,或者叫唤的动作就交给FlyBehavior QuackBehavior他们两个家伙去实现了。并且相应的getter setter表明鸭子的这些属性是可以随时动态设置的。
下面给出几种飞行或者叫唤的实现,让鸭子可以选择:
无法飞行:
package duck.beh;
import duck.beh.impl.FlyBehavior;
/**
* 这代表不能飞
* @author volador
*
*/
public class FlyNoWay implements FlyBehavior{
@Override
public void fly() {
System.out.println("i am so sorry,i can not fly..");
}
}
靠火箭飞行:
package duck.beh;
import duck.beh.impl.FlyBehavior;
/**
* 这是飞行的一种动作
* @author volador
*
*/
public class FlyWithRocket implements FlyBehavior{
@Override
public void fly() {
System.out.println("lalala,i am flying with rocket...");
}
}
正常飞行:
package duck.beh;
import duck.beh.impl.FlyBehavior;
/**
* 这是飞行的一种动作
* @author volador
*
*/
public class FlyWithWings implements FlyBehavior{
@Override
public void fly() {
System.out.println("xxx,i am flying with wings..");
}
}
正常叫唤:
package duck.beh;
import duck.beh.impl.QuackBehavior;
/**
* 这代表会呱呱叫
* @author volador
*
*/
public class Quack implements QuackBehavior{
@Override
public void quack() {
System.out.println("i can quack...");
}
}
不会叫唤:
package duck.beh;
import duck.beh.impl.QuackBehavior;
/**
* 这代表不会叫
* @author volador
*
*/
public class QuackNoWay implements QuackBehavior{
@Override
public void quack() {
System.out.println("so sorry that i can not quack...");
}
}
依靠电力交换:
package duck.beh;
import duck.beh.impl.QuackBehavior;
/**
* 借助电来叫
* @author volador
*
*/
public class QuackWtihEl implements QuackBehavior{
@Override
public void quack() {
System.out.println("i am flying whih electricity...");
}
}
好吧,是实现具体鸭子的时候了:
正常鸭:
package duck;
import duck.abs.Duck;
import duck.beh.FlyWithWings;
import duck.beh.Quack;
/**
* 这是个正常的鸭子
* @author volador
*
*/
public class StaDuck extends Duck{
/**
* 它可以飞,也可以叫
*/
public StaDuck(){
this.flyBehavior=new FlyWithWings();
this.quackBehavior=new Quack();
}
@Override
public void diaplay() {
System.out.println("i am a nomal duck..");
}
}
电子鸭:
package duck;
import duck.abs.Duck;
import duck.beh.FlyNoWay;
import duck.beh.QuackNoWay;
/**
* 这是个模型鸭
* @author volador
*
*/
public class ModelDuck extends Duck{
/**
* 它不能飞,也不能叫
*/
public ModelDuck(){
this.flyBehavior=new FlyNoWay();
this.quackBehavior=new QuackNoWay();
}
@Override
public void diaplay() {
System.out.println("i am a model duck..");
}
}
好,鸭子设计完毕,是看结果的时候了:
import duck.ModelDuck;
import duck.StaDuck;
import duck.abs.Duck;
import duck.beh.FlyWithRocket;
import duck.beh.QuackWtihEl;
public class DuckTest {
public static void main(String[] args){
Duck duck1=new StaDuck(); //它是正常鸭
duck1.diaplay();
duck1.performFly();
duck1.performQuack();
Duck duck2=new ModelDuck(); //它是一个模型鸭
duck2.diaplay();
duck2.performFly();
duck2.performQuack();
duck2.setFlyBehavior(new FlyWithRocket()); //让模型鸭可以借助火箭飞
duck2.setQuackBehavior(new QuackWtihEl()); //让模型鸭可以依靠电力来发声
duck2.performFly();
duck2.performQuack();
}
}
结果:
i am a nomal duck..
xxx,i am flying with wings..
i can quack...
i am a model duck..
i am so sorry,i can not fly..
so sorry that i can not quack...
lalala,i am flying with rocket...
i am flying whih electricity...
结果如我们所愿,总算能动态给鸭子转配上各种技能了。加入以后系统需要鸭子能坐着直升飞机飞,那么实现一个以直升飞机飞的实现实例,然后装配进你的鸭子里面就行了,不用去改动你的代码(完成了开闭原则)。
总结写上面,或许有另一种方式更能有助于大家理解:
每个人都玩过游戏,抽象一下,游戏中主要有3种东西,一种是角色,一种是角色所使用的武器,一种是技能。不同游戏角色可以使用不同的武器,不同的武器有不同的杀伤方式和伤害,不同的技能也一样。当然你也可以给你的角色装配上更加利害的武器和学习更利害的技能,这样,游戏中的角色就相当于上面我们设计的鸭子类,武器和技能就相当于鸭子类的各种行为属性。这样一来我们就可以动态装配给游戏的角色类各种武器,并让它学习各种技能了。