java设计模式之策略模式(一)

    设计模式之于程序员,是一种诱惑,不管你信不信,反正我信。不懂则必不会用,学习设计模式,在于在某个时候,需要实现某些功能,你会想到,哦,历经千山万水,原来你也在这里。网上资料云集,看一个例子看不懂,就多看几个,自然知其然且知其所以然。酷

    这里我会记录自己学习策略模式的例子,这个例子来自于Head First设计模式;并分享一个实例,来自于实际应用。

    Head First设计模式是从一个鸭子模拟游戏开始讲述策略模式的,游戏中会出现各种鸭子,一边游泳,一边呱呱叫。

  • 第一次设计是这样的,设计一个超类Duck,有呱呱叫行为quack,游泳行为swim,这两个行为在超类实现,被所有子类继承;另显示鸭子自己外观的方法display设计为抽象方法,由子类自己实现;这里有两个子类绿头鸭MallarDuck和红头鸭HedHeadDuck,类图如下:


  •  第二次的时候,需求有点小变更,需要让鸭子能飞。想都不用想,在超类里面加上一个fly方法就够了不是么!

 

 
    现在的问题是,一只橡皮鸭,居然也会飞(它不应该会飞)!因为在超类中增加了fly,所以所有的子类都具备了fly行为。既然这样不行,那么可以在橡皮鸭RubberDuck中覆盖超类的fly不久就可以了哇,就像覆盖quack呱呱叫方法一样!如果以后想加入诱饵鸭,它是一只木头假鸭,不会飞不会叫,同样需要覆盖quack和fly方法。

  • 那么问题来了,因为鸭子的行为在子类里不断地变化,并且让所有的子类都有这些行为是不恰当的,这就衍生了第一个设计原则:找出应用中可能需要变化之处,把它们独立出来,不和那些不需要变化的部分混合在一起。为了分开变化和不变化的部分,需要准备两组类,让它们完全远离Duck类,一个是fly相关的,一个是quack相关的,每一组类将实现各自的动作。而我们知道Duck类的fly和quack会随着鸭子的不同而变化,所以把它们抽取出来,建立一组新类来代表每个行为。我们希望设计有弹性,因为从一开始,鸭子的行为没有弹性,才让我们走上了这条不归路,我们希望能够指定行为到鸭子的实例,好比我们产生了一个绿头鸭,并指定特定的类型的飞行行为给它,因为这样,我们就可以在运行时动态地改变绿头鸭的飞行行为。所以衍生了第二个设计原则:针对接口编程,不针对实现编程。针对接口编程的真正意思是针对超类型编程

 这里是简单针对接口编程和针对实现编程的例子:

public abstract class Animal {
	protected abstract void makeSound();
}

class Dog extends Animal {
	@Override
	protected void makeSound() {
		bark();
	}

	void bark() {
		System.out.println("汪汪叫");
	}

}

class Cat extends Animal {
	@Override
	protected void makeSound() {
		meow();
	}

	void meow() {
		System.out.println("喵喵叫");
	}

}
 

这里是测试类:

class MainTest {
	public static void main(String[] args) {
		// 针对实现编程
		Dog dog = new Dog();
		dog.bark();
		
		// 针对接口编程
		Animal animal = new Cat();
		animal.makeSound();
	}
}
 
  •  现在我们实现鸭子的行为,类图如下:

 
                                        

  •  现在我们整合鸭子的行为,Duck变成了这样:




  •  现在整合代码
package src.designpattern.strategy.ex1;

/**
 * 鸭子超类
 * 
 * @author wusj
 * @date 2015-08-07
 */
public abstract class Duck {

	FlyBehaviour flyBehaviour;
	QuackBehaviour quackBehaviour;

	abstract void display();

	/**
	 * 所有的鸭子都会有用,漂浮起来,包括诱饵鸭
	 */
	public void swim() {
		System.out.println("All ducks float, even decoys.");
	}

	public void performQuack() {
		quackBehaviour.quack();
	}

	public void performFly() {
		flyBehaviour.fly();
	}
}
package src.designpattern.strategy.ex1;

/**
 * 用翅膀飞
 * 
 * @author wusj
 * @date 2015-08-07
 */
public class FlyWithWings implements FlyBehaviour {

	public void fly() {
		System.out.println("I'm flying.");
	}
}
package src.designpattern.strategy.ex1;

/**
 * 不会飞
 * 
 * @author wusj
 * @date 2015-08-07
 */
public class FlyNoWay implements FlyBehaviour {
	public void fly() {
		System.out.println("I can't fly.");
	}
}
package src.designpattern.strategy.ex1;

/**
 * 嘎嘎叫
 * 
 * @author wusj
 * @date 2015-08-07
 */
public class Quack implements QuackBehaviour {
	public void quack() {
		System.out.println("Quack.");
	}
}
package src.designpattern.strategy.ex1;

/**
 * 不会叫
 * 
 * @author wusj
 * @date 2015-08-07
 */
public class MuteQuack implements QuackBehaviour {
	public void quack() {
		System.out.println("Silence.");
	}
}
package src.designpattern.strategy.ex1;

/**
 * 绿头鸭
 * @author wusj
 * @date 2015-08-07
 */
public class MallarDuck extends Duck {

	/**
	 * 绿头鸭会呱呱叫,会飞
	 */
	public MallarDuck() {
		quackBehaviour = new Quack();
		flyBehaviour = new FlyWithWings();
	}

	@Override
	void display() {
		System.out.println("I'm a real Mallard duck.");
	}
}

测试类代码

class MiniDuckSimulator {
	public static void main(String[] args) {
		Duck mallard = new MallarDuck();
		mallard.performFly();
		mallard.performQuack();
	}
}

// 测试结果
// I'm flying.
// Quack.

其他代码暂略。

策略模式:定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

关于运用实例,请看java设计模式之策略模式应用:订单手续费计算

猜你喜欢

转载自wusj.iteye.com/blog/2233488