设计模式1-策略模式

227 阅读4分钟

1.场景问题解决

1.1 场景描述

模拟鸭子游戏,鸭子能叫,能游泳,鸭子还有各种品种,绿头鸭,红头鸭.

1.2 OO设计

  • 类图如下:

01策略模式-1.png

  • 鸭子抽象类 Duck---->叫声和游泳是普通方法,display是抽象方法,继承的类要实现该方法
public abstract class Duck {
	public Duck() {
	}
	public void Quack() {
		System.out.println("~~gaga~~");
	}
	public abstract void display();

	public void swim() {
		System.out.println("~~im swim~~");
	}
}
  • GreenHeadDuck 绿头鸭
public class GreenHeadDuck extends Duck {
	@Override
	public void display() {
		System.out.println("**GreenHead**");
	}
}

  • RedHeadDuck 红头鸭
public class RedHeadDuck extends Duck {
	@Override
	public void display() {
		System.out.println("**RedHead**");
	}
}

  • main
public class StimulateDuck {

	public static void main(String[] args) {

		GreenHeadDuck mGreenHeadDuck = new GreenHeadDuck();
		RedHeadDuck mRedHeadDuck = new RedHeadDuck();

		mGreenHeadDuck.display();
		mGreenHeadDuck.Quack();
		mGreenHeadDuck.swim();

		mRedHeadDuck.display();
		mRedHeadDuck.Quack();
		mRedHeadDuck.swim();
	}

}

1.3 需求变动,需要增加飞(fly())的功能

  • 鸭子抽象类 Duck---->叫声和游泳是普通方法,display是抽象方法,继承的类要实现该方法
public abstract class Duck {
	public Duck() {
	}
	public void Quack() {
		System.out.println("~~gaga~~");
	}
	public abstract void display();

	public void swim() {
		System.out.println("~~im swim~~");
	}
	public void Fly() {
			System.out.println("~~im fly~~");
	}
}
  • GreenHeadDuck 绿头鸭--继承默认就有了Fly功能
public class RedHeadDuck extends Duck {
	@Override
	public void display() {
		System.out.println("**RedHead**");
	}
}
  • RedHeadDuck 红头鸭 --没有fly功能还要继承覆盖
public class RedHeadDuck extends Duck {
	@Override
	public void display() {
		System.out.println("**RedHead**");
	}
	
	public void Fly() {
		System.out.println("~~I cannot fly~~");
	}
}

  • main
public class StimulateDuck {

	public static void main(String[] args) {

		GreenHeadDuck mGreenHeadDuck = new GreenHeadDuck();
		RedHeadDuck mRedHeadDuck = new RedHeadDuck();

		mGreenHeadDuck.display();
		mGreenHeadDuck.Fly();
		mGreenHeadDuck.Quack();
		mGreenHeadDuck.swim();

		mRedHeadDuck.display();
		mRedHeadDuck.Quack();
		mRedHeadDuck.swim();
		mRedHeadDuck.Fly();
	}

}

1.4 带来问题

  • 带来问题: 在的抽象父类中增加了fly()的方法,那么所有的子类都有了fly()的方法,如果RedHeadDuck鸭子不能飞翔,则还要覆盖fly()方法不让fly();

  • **继承的问题:**对类的局部改动,尤其超类的局部改动,会影响其他部分。影响会有溢出效应

  • 当方法越来越多的时候,个性化越来越多的时候,那么各个子类需要覆盖的方法越来越多。

2.用设计模式改进

2.1 分析

2.1.1 需要新的设计方式,应对项目的扩展性,降低复杂度:

1)分析项目变化与不变部分,提取变化部分,抽象成接口+实现; 2)鸭子哪些功能是会根据新需求变化的?叫声、飞行...

2.1.1 新增行为接口

接口:

public interface FlyBehavior{	
    void fly();
}
	 	
public interface QuackBehavior{	
    void quack();
};

好处:新增行为简单,行为类更好的复用,组合更方便。既有继承带来的复用好处,没 有挖坑

2.2 重新设计类图

01策略模式-2.png

2.3 重新设计代码

  • Duck
public abstract class Duck {
	FlyBehavior mFlyBehavior;
	QuackBehavior mQuackBehavior;

	public Duck() {

	}

	public void Fly() {
		mFlyBehavior.fly();
	}

	public void Quack() {
		mQuackBehavior.quack();
	}

	public abstract void display();

	public void SetQuackBehavoir(QuackBehavior qb) {
		mQuackBehavior = qb;
	}

	public void SetFlyBehavoir(FlyBehavior fb) {
		mFlyBehavior = fb;
	}

	public void swim() {
		System.out.println("~~im swim~~");
	}
}

  • FlyBehavior接口及实现
//FlyBehavior接口
public interface FlyBehavior {
	void fly();
}


public class	BadFlyBehavior implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("--BadFly--");
	}
}


public class	GoodFlyBehavior implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("--GoodFly--");
	}
}

public class	NoFlyBehavior implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("--NoFly--");
	}
}
  • QuackBehavior接口及实现
public	interface QuackBehavior {
	void quack();
};

public	class GaGaQuackBehavior implements QuackBehavior{
	@Override
	public void quack() {
		System.out.println("__GaGa__");
	}
}


public	class GeGeQuackBehavior implements QuackBehavior {
	@Override
	public void quack() {
		System.out.println("__GeGe__");
	}
}

public	class NoQuackBehavior implements QuackBehavior {
	@Override
	public void quack() {
		System.out.println("__NoQuack__");
	}
}

  • Duck及Duck实现
public abstract class Duck {

	FlyBehavior mFlyBehavior;
	QuackBehavior mQuackBehavior;

	public Duck() {

	}

	public void Fly() {
		mFlyBehavior.fly();
	}

	public void Quack() {
		mQuackBehavior.quack();
	}

	public abstract void display();

	public void SetQuackBehavoir(QuackBehavior qb) {
		mQuackBehavior = qb;
	}

	public void SetFlyBehavoir(FlyBehavior fb) {
		mFlyBehavior = fb;
	}

	public void swim() {
		System.out.println("~~im swim~~");
	}
}


public class GreenHeadDuck extends Duck {

	public GreenHeadDuck() {
		mFlyBehavior = new GoodFlyBehavior();
		mQuackBehavior = new GaGaQuackBehavior();
	}

	@Override
	public void display() {
		System.out.println("**GreenHead**");
	}
}

public class RedHeadDuck extends Duck {

	public RedHeadDuck() {
		mFlyBehavior = new BadFlyBehavior();
		mQuackBehavior = new GeGeQuackBehavior();
	}

	@Override
	public void display() {
		System.out.println("**RedHead**");
	}
}

  • Main
public class StimulateDuck {
	public static void main(String[] args) {

		Duck mGreenHeadDuck = new GreenHeadDuck();
		Duck mRedHeadDuck = new RedHeadDuck();

		mGreenHeadDuck.display();
		mGreenHeadDuck.Fly();
		mGreenHeadDuck.Quack();
		mGreenHeadDuck.swim();

		mRedHeadDuck.display();
		mRedHeadDuck.Fly();
		mRedHeadDuck.Quack();
		mRedHeadDuck.swim();
		mRedHeadDuck.display();
		mRedHeadDuck.SetFlyBehavoir(new NoFlyBehavior());
		mRedHeadDuck.Fly();
		mRedHeadDuck.SetQuackBehavoir(new NoQuackBehavior());
		mRedHeadDuck.Quack();
	}

}

3.设计模式总结

3.1 定义

策略模式: 分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设 定行为对象。原则就是:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为 算法的变化独立于算法的使用者。

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

3.2 分析思路

  • 1、分析项目中变化部分与不变部分,把他们独立出来,不要和那些不需要变化的代码混在一起
  • 2、多用组合少用继承;用行为类组合,而不是行为的继承。更有弹性
  • 3、设计模式有没有相应的库直接使用?有些库或框架本身就用某种设计模式设计的
  • 4、如果找不到适用的模式怎么办

3.3 总结设计原则

  • 设计原则1:分析项目中变化部分与不变部分,把他们独立出来,不要和那些不需要变化的代码混在一起
  • 设计原则2:针对接口编程,而不是针对实现编程
  • 设计原则3:多用组合,少用封装

4. 设计模式使用场景及注意

5.参考文章

读headFirst设计模式 - 策略模式

13种UML简介、工具及示例

内容总计于HeadFirst设计模式及相关视频