设计模式之----策略模式

摘要

策略模式:该模式定义了算法族,分别进行封装,让他们之间可以相互替换,该模式让算法的变化独立于使用算法的客户(定义:Head First)

该模式应用场景:某公司要开发一套模拟鸭子的游戏,鸭子会一边游泳,一边呱呱叫。使用面向对象的方式设计鸭子模型。

第一种实现方式:

设计一个Duck抽象超类。

       Duck

quack(){}//实现鸭子的叫声

swim(){}//鸭子都会游泳

display();//鸭子外观抽象类

    如果需要绿色鸭子,就继承Duck超类,实现里面的display()方法,如果需要红色鸭子类,也继承Duck超类,实现display()方法,想要什么颜色的鸭子就可以直接继承父类去实现,是不是很完美呢??

    突然有一天,需要一种会飞的鸭子,如果是你,该怎么实现呢,一个粗心的程序员是这样实现的:在Duck类中有增加了一个fly()方法,让鸭子会飞。这样继承Duck类的鸭子就都能飞了,但实际的需求并不是让所有的鸭子都会飞,这样设计当然就不合理了,也许现在你会说,那没有关系,子类直接覆盖父类的fly();方法,如果鸭子不需要飞,就空覆盖fly方法。

这样做有什么缺点呢?

代码在多个类中重复,很难知道所有鸭子的全部行为,如果又有一种新行为的鸭子,难道又要在Duck类中增加属性,然后再去覆盖所有的子类?

    也许这个时候你会想到使用接口了,你把fly()从Duck类中抽出,作为一个接口,让鸭子们自己实现fly方法,但是又并不是所有的鸭子都需要会飞的属性。这样就会导致代码无法重用。

    怎么样设计才是做合理的设计呢?请看下面的设计方式(代码实现):


IFlyBehavior:所有飞行类都实现该接口的fly方法

package com.wgy.cl.Interface;

public interface IFlyBehavior {
	public void fly();//飞行

}

IQuackBehavior:不同鸭子的叫声都实现该接口的quack方法

package com.wgy.cl.Interface;

public interface IQuackBehavior {
	public void quack();//叫声
}

 下面在定义鸭子所有的飞行方式。

FlyWithWingsImpl使用翅膀飞行类

package com.wgy.cl.Impl;

import com.wgy.cl.Interface.IFlyBehavior;

public class FlyWithWingsImpl implements IFlyBehavior {

	@Override
	public void fly() {
		System.out.println("I am flying with Wings");
	}

}

FlyNoWayImpl不能飞行的鸭子类

package com.wgy.cl.Impl;

import com.wgy.cl.Interface.IFlyBehavior;

public class FlyNoWayImpl implements IFlyBehavior {

	@Override
	public void fly() {
		System.out.println("I can't fly ~~");
	}

}

NoQuackImpl:不会叫的鸭子属性

package com.wgy.cl.Impl;

import com.wgy.cl.Interface.IQuackBehavior;

public class NoQuackImpl implements IQuackBehavior  {

	@Override
	public void quack() {
		System.out.println("I am 不会叫~~");
	}

}

QuackImpl:呱呱呱叫的鸭子

package com.wgy.cl.Impl;

import com.wgy.cl.Interface.IQuackBehavior;

public class QuackImpl implements IQuackBehavior {

	@Override
	public void quack() {
		System.out.println("I am 呱呱叫~~");
	}

}

SqueakImpl:吱吱叫的鸭子


鸭子的超类Duck实现:所有鸭子都继承该类

package com.wgy.cl;

import com.wgy.cl.Interface.IFlyBehavior;
import com.wgy.cl.Interface.IQuackBehavior;

/**
 * 让不同类型的鸭子都继承该抽象类
 * @author SAMSUNG SDS
 *
 */
public abstract class Duck {
	public IFlyBehavior iFlyBehavior;
	
	public IQuackBehavior iQuackBehavior;
	
	public void perFormFly(){//鸭子的飞行方式
		iFlyBehavior.fly();//
	}
	public void perFormQuack(){//鸭子的叫声
		iQuackBehavior.quack();
	}
	
	public void swim(){//所有鸭子都会游泳
		System.out.println("All Duck Can swim~~");
	}
	
	public abstract void display();//每个鸭子的外形不一样
	
	//动态设置鸭子的飞行模式,可以改变飞行方式,nb不nb
	public void setFlyBehavior(IFlyBehavior fl){
		iFlyBehavior = fl;
	}
	
	//可以改变鸭子的叫声
	public void setQuackBehavior(IQuackBehavior qb){
		iQuackBehavior = qb;
	}

}

下来就来造一只绿头鸭MallardDuck

package com.wgy.cl;

import com.wgy.cl.Impl.FlyWithWingsImpl;
import com.wgy.cl.Impl.QuackImpl;

/**
 * 绿头鸭
 * @author SAMSUNG SDS
 */
public class MallardDuck extends Duck {

	//绿头鸭继承抽象类Duck
	public MallardDuck(){
		iFlyBehavior = new FlyWithWingsImpl();//翅膀飞行
		iQuackBehavior = new QuackImpl();//呱呱叫
	}
	
	public void display() {
		System.out.println("I am MallardDuck ~~ ");
	}

}

测试绿头鸭

package com.wgy.cl;

import com.wgy.cl.Impl.NoQuackImpl;

public class TestDuck {

	/**
	 * 鸭子的测试类
	 * @param args
	 */
	public static void main(String[] args) {
		Duck mallard = new MallardDuck();//实例化一个绿鸭子
		mallard.display();//鸭子的外形
		mallard.perFormFly();//鸭子的飞行方式
		mallard.perFormQuack();//鸭子的叫声
		
	}

}

运行结果:

I am MallardDuck ~~ 

I am flying with Wings

I am 呱呱叫~~

如果让绿头鸭的叫声动态改变(不修改MallardDuck类),该怎么实现呢?其实很简单。

package com.wgy.cl;

import com.wgy.cl.Impl.NoQuackImpl;

public class TestDuck {

	/**
	 * 鸭子的测试类
	 * @param args
	 */
	public static void main(String[] args) {
		Duck mallard = new MallardDuck();//实例化一个绿鸭子
		mallard.display();//鸭子的外形
		mallard.perFormFly();//鸭子的飞行方式
		mallard.perFormQuack();//鸭子的叫声
		//动态改变鸭子的叫声
		mallard.setQuackBehavior(new NoQuackImpl());
		mallard.perFormQuack();
	}

}

像创建MallardDuck鸭一样,我们可以创建具有不同属性的鸭子,只需要修改鸭子构造器里面的属性就可以了。

public MallardDuck(){
		iFlyBehavior = new FlyWithWingsImpl();//翅膀飞行(根据鸭子的属性不同,可以选择不同的行为属性)
		iQuackBehavior = new QuackImpl();//呱呱叫
	}

这就是策略模式的应用场景,设计原则就是通过接口编程,而不是针对于实现编程,多用组合,少用继承的原则!

IT家园
IT家园

网友最新评论 (0)