策略模式Java实现

都是被产品逼的!

目前广为流传的设计模式都是前辈们的重要经验,都是在实践中检验的真理。
鸭子游戏是目前最为广泛的策略模式入门。
为什么说策略模式是被产品逼出来的呢?
需求
鸭子可以有外型(display),可以叫(quack),可以游泳(swim)有各种各样的鸭子, eg:绿头鸭(MallardDuck),红头鸭
(RedHeadDuck),橡皮鸭(RubberDuck)…要求采用OO的设计方式

实现这个需求还是很简单的
一、我们先来一个鸭子父类 里面写抽象方法外型(display)和行为 叫(quack),可以游泳(swim)
二、各种鸭子继承父类
三、实现各自的外形
好了 你需求完成了真棒

产品现在来个另外一个需求 我们要鸭子会飞!
没办法 改呗!
Duck父类继续加入一个飞的行为
完工!下班!

产品又来需求了,不过这次来了个比较奇葩的需求。他说橡皮鸭子不能飞!
啊这!这也简单!
子类中将飞的方法重写不就解决了!

产品又双叒叕来需求了,各种鸭子都来了,能飞不能叫,能叫不能飞,不能叫不能飞等等
真实烦死了!!!!!!!!!
总不能一直修改下去!这样继承的意义何在呢?
改用接口?这样所有的代码都无法复用了!简直就是噩梦!!!

因此前辈们有了前车之鉴!换了一种新的方式来实现次功能!!!

策略模式

以鸭子游戏为例

我们先写一个行为的接口

public interface FlyBav {
    
    	
		public void fly();
}


public interface QuackBav {
    
    	
	public void quack();
}

然后实现各种行为
能飞


public class CanFly  implements FlyBav{
    
    

	@Override
	public void fly() {
    
    
		// TODO 自动生成的方法存根
		System.out.println("我不能飞!");
		
	}

}

不能飞

public class CanNotFly implements FlyBav{
    
    

	@Override
	public void fly() {
    
    
		// TODO 自动生成的方法存根
		System.out.println("我能飞!");
	}

}

能叫

public class CanQuack implements QuackBav{
    
    

	@Override
	public void quack() {
    
    
		// TODO 自动生成的方法存根
		System.out.println("我能叫!");
		
	}

}

不能叫

public class CanNotQuack implements QuackBav{
    
    

	@Override
	public void quack() {
    
    
		// TODO 自动生成的方法存根
		System.out.println("我不能叫!");
	}

}

我们会改变的前置需求解决了

我们来写鸭子的父类
父类里声明会变的行为变量
使用构造函数进行初始化 因此我便无需关系鸭子具体能不能飞能不能叫 一切由需求觉定

public abstract class Duck {
    
    
	
	
	//鸭子这两种行为具体是什么我不关心 能不能飞 能不能叫由用户本身决定
	
	//飞的行为 
	private FlyBav flyBav;
	//叫的行为
	private QuackBav quackBav;
	
	//构造函数 并且不声明无参构造 即使用次对象必须对确定对象是否能飞能叫
	public Duck(FlyBav flyBav, QuackBav quackBav) {
    
    
		this.flyBav = flyBav;
		this.quackBav = quackBav;
	}
	
	
	//子类需要实现dispaly方法
	public abstract void display();
	
	
	//飞的方法 能不能飞委托给FlyBav 由传入的值确定能不能飞
	public void fly() {
    
    
		flyBav.fly();
	}
	
	//叫的方法 能不能叫委托给QuackBav 由传入的值确定能不能叫
	public void quack() {
    
    
		quackBav.quack();
	}
	
	//鸭子游戏
	public void play() {
    
    
		this.display();
		this.fly();
		this.quack();
	
	}
	

}

各种鸭子的子类
绿鸭子

public class GreenDuck extends Duck{
    
    

	public GreenDuck(FlyBav flyBav, QuackBav quackBav) {
    
    
		super(flyBav, quackBav);
		// TODO 自动生成的构造函数存根
	}

	@Override
	public void display() {
    
    
		// TODO 自动生成的方法存根
		System.out.println("我是一只绿鸭子!");
	}
	
	

}

橡皮鸭子

public class RubberDuck extends Duck{
    
    

	public RubberDuck(FlyBav flyBav, QuackBav quackBav) {
    
    
		super(flyBav, quackBav);
		// TODO 自动生成的构造函数存根
	}

	@Override
	public void display() {
    
    
		// TODO 自动生成的方法存根
		System.out.println("我是一只橡皮鸭子!");
	}

}

测试类

public class DuckTest {
    
    
	
	
	public static void main(String[] args) {
    
    
		
		
		GreenDuck greenDuck = new GreenDuck(new CanFly(), new CanQuack());
		
		RubberDuck rubberDuck = new RubberDuck(new CanNotFly(), new CanQuack());
		

		
		greenDuck.play();
		rubberDuck.play();

	}

}

在这里插入图片描述
大功告成!

策略模式的优点

那么策略模式有什么优点呢?
别急!
新的需求来了,产品要一个北京烤鸭!不能飞,不能叫!
怎么办?
简单!直接来一个北京烤鸭的子类就解决了!其余代码完全不需要改动!

最大的优点
有新的需求不需要改动原有的代码,因为只要代码改动了何其相关的一切都需要重新测试!不改动原有代码就是很棒的设计!

实现
北京烤鸭 新的需求来了原有代码完全不需要改动

public class BJDuck extends Duck{
    
    

	public BJDuck(FlyBav flyBav, QuackBav quackBav) {
    
    
		super(flyBav, quackBav);
		// TODO 自动生成的构造函数存根
	}

	@Override
	public void display() {
    
    
		// TODO 自动生成的方法存根
		System.out.println("我是北京烤鸭!");
		
	}

}

测试类

public class DuckTest {
    
    
	
	
	public static void main(String[] args) {
    
    
		
		
		GreenDuck greenDuck = new GreenDuck(new CanFly(), new CanQuack());
		
		RubberDuck rubberDuck = new RubberDuck(new CanNotFly(), new CanQuack());
		
		BJDuck bjDuck = new BJDuck(new CanNotFly(), new CanNotQuack());
		
		greenDuck.play();
		rubberDuck.play();
		bjDuck.play();
	}

}

在这里插入图片描述

Guess you like

Origin blog.csdn.net/Carryi/article/details/120522660
Recommended