最近在学设计模式,这些博客权当笔记。
Strategy Pattern 策略模式
策略模式简介:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
现在有一个需求,有一个Duck鸭子的父类,需要用父类来生出很多不同种类的鸭子子类,大家都知道真实的鸭子会叫,有的鸭子会飞,(我也不知道会不会飞),但是还有玩具鸭子,例如橡皮鸭子(一捏就会吱吱叫,但是不会飞)、木头鸭子(怎么捏也不会叫,也不会飞),还有唐老鸭(唐老鸭背着喷气筒用火箭飞,还会呱呱叫)。这只是暂时的需求,后期还会根据新生的鸭子产生对应的需求。
这种需求是很简单的需求,只需要有一个Duck父类,在父类里设计一个fly和一个quack方法,让子类来继承它就哦了。
如果Duck父类实现了fly(用翅膀飞)和quack(呱呱叫)方法,那么所有的鸭子子类都会继承这两个方法,代码简介了很多,而且子类可以通过覆盖这两个方法去实现不同的功能。
但是如果有橡皮鸭子和木头鸭子的出现,橡皮鸭子会吱吱叫而不是父类的呱呱叫,但是橡皮鸭子不会飞;木头鸭子既不会叫也不会飞。
针对这种情况可以将父类的fly和quack方法设置成抽象方法,让子类具体实现,这种方式有弊端,那就是如果有大量不同的子类就会造成在子类中fly和quack方法里代码的重复。
还有一种方法就是父类的fly和quack方法实现大多数鸭子的fly和quack功能,少数的鸭子子类只需要覆盖这两个方法即可,但是鬼知道大多数鸭子的fly和quack功能是什么样的、少数鸭子的fly和quack功能又是什么样的,并且在这个需求一直改变的现况下,用这两种方式会经常去改原有的代码。
针对这种情况可以将父类的fly和quack方法设置成抽象方法,让子类具体实现,这种方式有弊端,那就是如果有大量不同的子类就会造成在子类中fly和quack方法里代码的重复。
还有一种方法就是父类的fly和quack方法实现大多数鸭子的fly和quack功能,少数的鸭子子类只需要覆盖这两个方法即可,但是鬼知道大多数鸭子的fly和quack功能是什么样的、少数鸭子的fly和quack功能又是什么样的,并且在这个需求一直改变的现况下,用这两种方式会经常去改原有的代码。
我们可以使用策略模式来实现该功能,具体的操作就是把需求中可能会改变的东西给拿出来,让它和不变的东西分离开来,这样需求再改变的时候只需要修改可变的部分,而不用去修改原有的不变的代码。代码变化引起的不经意后果变少,系统变得更有弹性。这就是我们的设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。意思就是,如果每次新的需求一来,都会使某方面的代码发生变化,那么你就可以确定,这部分代码需要被抽出来,和其他稳定的代码有所区分。这样的概念很简单,几乎是每个设计模式背后的精神所在。所有的模式都提供一种方法让"系统中的某部分改变不影响其他部分"。
我们知道Duck类的fly和quack方法会随着鸭子的不同而有所改变,所以我们把这两个方法从Duck类中抽出来,建立一组新类来代表每个行为。我们希望一切能有弹性,因为每个鸭子的实现类不确定,所以fly和quack方法的具体实现也不确定,我们就可以设计一个FlyBehavior和Quackehavior接口,然后每增加一种fly方式,我们就增加一个新类来实现FlyBehavior接口;同样每增加一个quack方式,我们就增加一个新类类实现QuackBehavior接口。这样就可以动态的去实现fly和quack方法,而不需要在编译期写死。
<span style="font-size:18px;">package wang.behavior;
public interface FlyBehavior {
void fly();
}</span>
<span style="font-size:18px;">package wang.behavior;
public interface QuackBehavior {
<span style="white-space:pre"> </span>void quack();
}
</span>
package wang.oldservice;
/**
* @author Wang
*/
public abstract class Duck {
//抽象方法,让子类去实现自己要展示的是什么
public abstract void display();
/**
* 所有的鸭子子类都会继承该方法,都有飞的功能
*/
public void fly(){
System.out.println("I am Flying~");
}
/**
* 所有的鸭子子类都会继承该方法,都有呱呱叫的功能
*/
public void quack(){
System.out.println("呱呱呱~~");
}
}
package wang.behavior.impl;
import wang.behavior.FlyBehavior;
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("我用翅膀飞....");
}
}
<pre name="code" class="java">不会飞的行为:
package wang.behavior.impl;
import wang.behavior.FlyBehavior;
public class CannotFly implements FlyBehavior {
@Override
public void fly() {
System.out.println("我不会飞...");
}
}
用火箭飞行的唐老鸭:
package wang.behavior.impl;
import wang.behavior.FlyBehavior;
public class FlyWithRocket implements FlyBehavior {
@Override
public void fly() {
System.out.println("我用火箭筒飞...");
}
}
呱呱叫的行为:
package wang.behavior.impl;
import wang.behavior.QuackBehavior;
public class GuaGuaQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("呱呱 呱呱...");
}
}
吱吱叫的行为:
package wang.behavior.impl;
import wang.behavior.QuackBehavior;
public class ZhiZhiQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("吱吱 吱吱...");
}
}
不会叫的行为:
package wang.behavior.impl;
import wang.behavior.QuackBehavior;
public class CannotQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("<<我不会叫>>");
}
}
接下来就是要实现具体的鸭子子类了
真是的鸭子:会呱呱叫,会用翅膀飞:
package wang.service;
import wang.behavior.impl.FlyWithWings;
import wang.behavior.impl.GuaGuaQuack;
public class RealDuck extends Duck {
public RealDuck() {
flyBehavior = new FlyWithWings();
quackBehavior = new GuaGuaQuack();
}
@Override
public void display() {
System.out.println("我是一个真鸭子");
}
}
橡皮鸭子,会吱吱叫,但是不会飞:
package wang.service;
import wang.behavior.impl.CannotFly;
import wang.behavior.impl.ZhiZhiQuack;
public class XiangpiDuck extends Duck {
public XiangpiDuck() {
flyBehavior = new CannotFly();
quackBehavior = new ZhiZhiQuack();
}
@Override
public void display() {
System.out.println("我是一个橡皮鸭子...");
}
}
木头鸭子,不会飞,也不会叫:
package wang.service;
import wang.behavior.impl.CannotFly;
import wang.behavior.impl.CannotQuack;
public class WoodenDuck extends Duck {
public WoodenDuck() {
flyBehavior = new CannotFly();
quackBehavior = new CannotQuack();
}
@Override
public void display() {
System.out.println("我是一个木头鸭子");
}
}
会用火箭飞的唐老鸭,也会呱呱叫:
package wang.service;
import wang.behavior.impl.FlyWithRocket;
import wang.behavior.impl.GuaGuaQuack;
public class DuckFlyWithRocket extends Duck {
public DuckFlyWithRocket() {
flyBehavior = new FlyWithRocket();
quackBehavior = new GuaGuaQuack();
}
@Override
public void display() {
System.out.println("我会用火箭飞...");
}
}
这样我们就可以让所有的鸭子子类任意组合fly和quack行为,因为fly和quack行为是独立的,谁都可以任意拿来用,只要遵循委托的规则。
测试:
package wang.behavior.test;
import wang.service.Duck;
import wang.service.DuckFlyWithRocket;
import wang.service.RealDuck;
import wang.service.WoodenDuck;
import wang.service.XiangpiDuck;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
Duck duck1 = new RealDuck();
duck1.display();
duck1.fly();
duck1.quack();
System.out.println("----------------------------");
Duck duck2 = new XiangpiDuck();
duck2.display();
duck2.fly();
duck2.quack();
System.out.println("----------------------------");
Duck duck3 = new WoodenDuck();
duck3.display();
duck3.fly();
duck3.quack();
System.out.println("----------------------------");
Duck duck4 = new DuckFlyWithRocket();
duck4.display();
duck4.fly();
duck4.quack();
}
}
输出结果为:
我是一个真鸭子
我用翅膀飞....
呱呱 呱呱...
----------------------------
我是一个橡皮鸭子...
我不会飞...
吱吱 吱吱...
----------------------------
我是一个木头鸭子
我不会飞...
<<我不会叫>>
----------------------------
我会用火箭飞...
我用火箭筒飞...
呱呱 呱呱...
我用翅膀飞....
呱呱 呱呱...
----------------------------
我是一个橡皮鸭子...
我不会飞...
吱吱 吱吱...
----------------------------
我是一个木头鸭子
我不会飞...
<<我不会叫>>
----------------------------
我会用火箭飞...
我用火箭筒飞...
呱呱 呱呱...