策略模式-设计模式

策略模式的定义:
策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
策略模式:
定义了一组算法(业务规则);
封装了每个算法;
这族的算法运行时可互换代替(interchangeable)。
应用场景:
1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
一、策略模式的问题引入:

  • 有一家游戏公司,制作一款鸭子游戏.在这个鸭子游戏中,角色都是鸭子,
  • 不同的鸭子之间,有共性,所以为了提高代码的重用性。开发人员,就制作了
  • 一个鸭子的父类Duck,把这些鸭子的共性上提到一个父类中。
    在这里插入图片描述
abstract class Duck{
	public void quack() {
		System.out.println("嘎嘎");
	}
	public void swim() {
		System.out.println("游泳...");
	}
	public abstract void display();
	
}

class MallardDuck extends Duck{
	public void display() {
		System.out.println("外观是野鸭!~");
	};
}

class HeadRedDuck extends Duck{
	public void display() {
		System.out.println("外观是红头鸭!~");
	};
}

public class AppTesta {
	public static void main(String[] args) {
		MallardDuck mallardDuck = new MallardDuck();
		mallardDuck.quack();
		mallardDuck.display();
		mallardDuck.swim();
	}
}

此时看不出什么问题。

2.问题发生:橡皮鸭能飞了

  • 游戏公司 的老总们开会,得出一个提高本公司竞争游戏竞争力的方案,
  • 要求让游戏中的鸭子能飞起来!把其他竞争者远远甩在身后!
    *程序员:是时候展现我们面向对象程序员的威力了!我只需要在父类Duck
    *中,添加一个fly方法。那么所有Duck的子类,也都共用了fly方法.
    *此时:问题看似解决了,但实际上出现了更麻烦的问题。所有的Duck的子类鸭子都会飞了。
    *要知道,父类中的方法, 并不是所有子类都能通用的!!比如:橡皮鸭!
    *橡皮鸭是没有生命的,不能飞。结果搞得所有的鸭子都能飞了。

在这里插入图片描述

abstract class Duck{
	public void quack() {
		System.out.println("嘎嘎");
	}
	public void swim() {
		System.out.println("游泳...");
	}
	
	public void fly() {
		System.out.println("我飞~~~");
	}
	
	public abstract void display();
	
	
}

class MallardDuck extends Duck{
	public void display() {
		System.out.println("外观是野鸭!~");
	};
}

class HeadRedDuck extends Duck{
	public void display() {
		System.out.println("外观是红头鸭!~");
	};
}

class RubberDuck extends Duck{
	//因为橡皮鸭不会像真实的鸭子一样叫,所以模拟了橡皮鸭特有的
	//叫声。所以重写了父类的quack方法.
	public void quack() {
		System.out.println("吱吱叫...");
		
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("外观是橡皮鸭");
	}
	
	public void fly() {
		System.out.println("橡皮鸭不能飞");
	}
	
}

public class AppTestb {
	public static void main(String[] args) {
		Duck m = new RubberDuck();
		m.quack();
		m.display();
		m.swim();
		m.fly();
	}
}
  • 看起来,问题好像解决了,但是问题并没有解决,变化总是不断地出现。程序员就要在每次添加新的鸭子角色时,都要判断,新的鸭子角色,会不会叫,会不会飞。针对于不同的鸭子,更有不同的处理方法。这样也很麻烦,只不过是从一个噩梦跌入了另一个噩梦。

3.提出改进措施:

  • 针对于b包中的问题,程序员需要判断每个鸭子子类,
  • 谁会不会叫,谁会不会飞,
  • 不会叫的,就重写quack方法,
  • 不会飞的,就重写fly方法,
  • 这个工作量是很大的。
    在这里插入图片描述
abstract class Duck{	
	public void swim() {
		System.out.println("游泳...");
	}
	public abstract void display();
}

interface quackable{
	void quack();
}

interface flyable{
	void fly();
}

class MallardDuck extends Duck implements quackable,flyable{
	public void display() {
		System.out.println("外观是野鸭!~");
	}

	@Override
	public void quack() {
	System.out.println("嘎嘎叫");
		
	}

	@Override
	public void fly() {
		System.out.println("我飞");
		
	};
}

class HeadRedDuck extends Duck implements flyable,quackable{
	public void display() {
		System.out.println("外观是红头鸭!~");
	}

	@Override
	public void quack() {
		System.out.println("嘎嘎叫");
		
	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("我飞!~~~~~");
	};
}

class RubberDuck extends Duck implements quackable{
	//因为橡皮鸭不会像真实的鸭子一样叫,所以模拟了橡皮鸭特有的
	//叫声。所以重写了父类的quack方法.
	public void quack() {
		System.out.println("吱吱叫...");
		
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("外观是橡皮鸭");
	}	
}

class DecoyDuck extends Duck{

	@Override
	public void display() {
		System.out.println("外观是诱饵鸭~~");
		
	}
	
}

public class AppTestc {
	public static void main(String[] args) {
		//向上转型发生时,子类独有的方法掉不了.只能把其变成
		//子类型,然后再调用fly方法.
		 RubberDuck m = new RubberDuck();
		m.display();
		m.swim();
		m.quack();
	}
}
  • 思考:这样问题解决了吗?没有!
  • 以前是每加入一个新的鸭子角色,程序员就要判断这个新鸭子角色是否会飞,
  • 是否会叫,不会飞的就重写飞方法,不会叫的就重写叫方法。
  • 现在是每加入一个新的鸭子角色,程序员就要判断这个新鸭子角色是否会飞,
  • 是否会叫,不会飞的就不实现flyable接口,不会叫的就不实现quackable接口。
  • 如此,程序员仍然没有减少工作量啊?仍然要不断地判断新鸭子角色。
  • 另外一个缺点就是,fly和quack方法没有重用性可言。
  • 比如有48种鸭子,有8种不会飞,那么飞方法就要在40个鸭子子类中一共重复40次!
  • 此时,应有杠点:
  • 老师,从jdk1.8开始,接口中的方法就有默认实现即可,只写1次。
  • 解释:对于48种鸭子,有12种飞行方法,又该如何?飞行方法,仍然在子类中重复。

4.引出策略模式:

  • 针对于c包中的问题,修改代码如下:
  • 是时候,把飞行和叫方法,从鸭子类中分离出来了!注意:这里的分离,与c包中分离不一样。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
interface FlyBehavior {
	 void fly();
}


class FlyWithWings implements FlyBehavior{

	@Override
	public void fly() {
		System.out.println("用翅膀飞~~");
		
	}
	
}

class FlyWithRocket implements FlyBehavior{
	public void fly() {
		System.out.println("用火箭飞~~");
	}
}

class FlyWithKick implements FlyBehavior{
	public void fly() {
		System.out.println("被人踢飞~~");
	}
}

class FlyNoWay implements FlyBehavior {

	@Override
	public void fly() {
		System.out.println("目前不会飞~~");
	}
	
}


interface QuackBehavior{
	void quack();
}
class Quack implements QuackBehavior{
	public void quack() {
		System.out.println("呱呱叫");
	}
}
class Squeak implements QuackBehavior{
	public void quack() {
		System.out.println("橡皮鸭吱吱叫");
	}
}
class MuteQuack implements QuackBehavior{
	public void quack() {
		System.out.println("不会叫");
	}
}


abstract class Duck {	
	
	protected FlyBehavior fb;
	protected QuackBehavior qb;
	
	public void swim() {
		System.out.println("游泳...");
	}
	public abstract void display();
	
	public void performFly() {
		fb.fly();
	}
	public void performQueak() {
		qb.quack();
	}
	public FlyBehavior getFb() {
		return fb;
	}
	public void setFb(FlyBehavior fb) {
		this.fb = fb;
	}
	public QuackBehavior getQb() {
		return qb;
	}
	public void setQb(QuackBehavior qb) {
		this.qb = qb;
	}
	
}



class MallardDuck extends Duck{
	public MallardDuck() {
		fb = new FlyWithWings();
		qb = new Quack();
	}
	
	
	public void display() {
		System.out.println("外观是野鸭!~");
	}
	
}

class HeadRedDuck extends Duck {
	public HeadRedDuck(){
		fb = new FlyWithWings();
		qb = new Quack();
	}
	public void display() {
		System.out.println("外观是红头鸭!~");
	}

	
}

class RubberDuck extends Duck {

	public RubberDuck() {
		fb = new FlyNoWay();
		qb = new Squeak();
	}
	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("外观是橡皮鸭");
	}	
}

class DecoyDuck extends Duck{

	public DecoyDuck() {
		fb = new FlyNoWay();
		qb = new MuteQuack();
	}
	@Override
	public void display() {
		System.out.println("外观是诱饵鸭~~");
	}
	
}

//=========================方法可以扩展
class FlyWithRobotCat implements FlyBehavior{
	public void fly() {
		System.out.println("头上绑个竹蜻蜓飞~~");
	}
}

public class AppTestd {
	public static void main(String[] args) {
		//向上转型发生时,子类独有的方法掉不了.只能把其变成
		//子类型,然后再调用fly方法.
		Duck r = new RubberDuck();
		r.performFly();
		
		//**运行时改变了方法行为**
		r.setFb(new FlyWithKick());
		r.performFly();
		
		r.performQueak();
		r.display();
		r.swim();
	}
}
  • 此时,针对于48种鸭子,有12种飞行方法而言,每种飞行方法,写一次!
  • 这就是传说中的策略模式。
  • 策略模式关键点:不让鸭子直接实现接口,单独让一个类实现接口,让这个类组合到鸭子的具体类中。
  • 策略模式体现了组合优于继承原则、开闭原则和单一职责原则。

二、策略模式举例:在策略模式中,运行时替换是其独有的亮点。

设计一款游戏,使得小人在运行时,吃到什么道具,就发出什么攻击。

package q_strategy.a;

//定义一个weapon接口,让道具实现不同的攻击方式.
interface Weapon{
	public void attack();
}

class Sword implements Weapon{

	//java中如果你没有声明任何构造器,编译器会自动帮你创建个默认无参构造器的
	//就是这样,你没有显示的写上一个构造器,那么在你编译的时候编译器就给你创建了
	@Override
	public void attack() {
		// TODO Auto-generated method stub
		System.out.println("用剑砍~~");
	}
	
}

class Axe implements Weapon{

	@Override
	public void attack() {
		// TODO Auto-generated method stub
		System.out.println("三板斧");
	}
	
}
class Arrow implements Weapon{

	@Override
	public void attack() {
		// TODO Auto-generated method stub
		System.out.println("用矛刺");
	}
	
}

class Role{
	private String name;
	private Weapon weapon;
	
	public Role(String name) {
		this.name = name;
	}
	
	public Weapon getWeapon() {
		return weapon;
	}

	public void setWeapon(Weapon weapon) {
		this.weapon = weapon;
	}
	
	//注意这是最关键的一步:fight中的内容不能写死,而是要根据weapon中赋值的不同,
	//选择不同的攻击方式。
	public void fight() {
		weapon.attack();
	}
	
}
//===============================此外,还可以扩充

class Gun implements Weapon{

	@Override
	public void attack() {
		// TODO Auto-generated method stub
		System.out.println("用机关枪哒哒哒~~~~");
	}
	
}
public class testa {
	public static void main(String[] args) {
		Role role = new Role("骑士");
		
		//运行时调用剑
		role.setWeapon(new Sword());
		
 		role.fight();
 		role.fight();
 		role.fight();
 		
 		//捡到斧头刀具
 		role.setWeapon(new Axe());
 		role.fight();
 		role.fight();
 		role.fight();
 		
 		//捡到长矛道具
 		role.setWeapon(new Arrow());
 		role.fight();
 		role.fight();
 		role.fight();
 		//捡到枪道具
 		role.setWeapon(new Gun());
 		role.fight();
 		role.fight();
 		role.fight();
	}
	
	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值