Gof-策略模式
作者:互联网
继续打卡设计模式
今天来聊一下的是策略模式
一、实际问题
- 有各种鸭子(比如 野鸭、北京鸭、水鸭等, 鸭子有各种行为,比如 叫、飞行等)
- 显示鸭子的信息
【问题分析】:
我们想如果直接编码我们可以写一个抽象的鸭子类。里面有叫 飞行 游泳等功能。然后我们让其它鸭子来继承这个抽象类。
于是其它的子类来重写里面的方法,来完成对应的功能
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public abstract class Duck {
public Duck() {
}
public abstract void display();//显示鸭子信息
public void quack() {
System.out.println("鸭子嘎嘎叫~~");
}
public void swim() {
System.out.println("鸭子会游泳~~");
}
public void fly() {
System.out.println("鸭子会飞翔~~~");
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public class PekingDuck extends Duck {
@Override
public void display() {
System.out.println("~~北京鸭~~~");
}
//因为北京鸭不能飞翔,因此需要重写fly
@Override
public void fly() {
System.out.println("北京鸭不能飞翔");
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public class ToyDuck extends Duck{
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("玩具鸭");
}
//需要重写父类的所有方法
public void quack() {
System.out.println("玩具鸭不能叫~~");
}
public void swim() {
System.out.println("玩具鸭不会游泳~~");
}
public void fly() {
System.out.println("玩具鸭不会飞翔~~~");
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public class WildDuck extends Duck{
@Override
public void display() {
System.out.println(" 这是野鸭 ");
}
}
这是比较传统的做法
那么我们现在思考一下。由于都继承了Duck类。所有fly方法让所有子类都会飞。这是不正确的。
后续一旦对父类改动,影响也是非常巨大的。
所以我们解决的思路就是策略模式
二、策略模式来解决该问题
使用策略模式第一步我们需要定义一个策略组,然后把它们分别封装起来。
比如上面提到的鸭子飞翔的问题。我们可以定义一些能力标准。例如飞翔技术很好 、飞翔技术一般、不会飞翔
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public interface FlyBehavior {
void fly();
}
有了接口之后我们来依次定义这三个实现类
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public class GoodFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println(" 飞翔技术高超 ~~~");
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public class BadFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("飞行技术一般");
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public class NoFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("不会飞翔");
}
}
为了对比比较明显我们在动态的对鸭子的一个属性来进行一些定义。(只是为了对比明显)
我们需要对鸭子的叫声来进行一些定义
例如有些鸭子会叫 有些鸭子不会叫等等。方式和定义飞翔一样
/**
* @author: 德鑫
* @since: 2021/02/07
*/
public interface QuackBehavior {
void quack();
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/18
*/
public class GoodQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("会叫~~~");
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/18
*/
public class NoQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("不会叫~~~");
}
}
有了以上的这些策略组之后我们就需要定义我们的抽象类鸭
package com.atguigu.strategy.improve;
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {
}
public abstract void display();//显示鸭子信息
public void quack() {
// System.out.println("鸭子嘎嘎叫~~");
if(quackBehavior != null){
quackBehavior.quack();
}
}
public void swim() {
System.out.println("鸭子会游泳~~");
}
public void fly(){
//改进
if(flyBehavior != null) {
flyBehavior.fly();
}
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
然后定义三只鸭子来继承这个基类。
北京鸭
package com.atguigu.strategy.improve;
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/07
*/
public class PekingDuck extends Duck {
public PekingDuck() {
flyBehavior = new BadFlyBehavior();
}
@Override
public void display() {
System.out.println("~~北京鸭~~~");
}
}
玩具鸭
package com.atguigu.strategy.improve;
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/18
*/
public class ToyDuck extends Duck{
public ToyDuck() {
flyBehavior = new NoFlyBehavior();
quackBehavior = new NoQuackBehavior();
}
@Override
public void display() {
System.out.println("玩具鸭");
}
//需要重写父类的所有方法
public void swim() {
System.out.println("玩具鸭不会游泳~~");
}
}
野鸭
package com.atguigu.strategy.improve;
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/18
*/
public class WildDuck extends Duck{
//构造器,传入FlyBehavor 的对象
public WildDuck() {
flyBehavior = new GoodFlyBehavior();
}
@Override
public void display() {
System.out.println(" 这是野鸭 ");
}
}
最后写一个客户端来测试
我们测试的时候第一步肯定是需要创建出对应的鸭子。然后查看这些鸭子的自身属性。注意我们的策略组现在是通过属性注入到我们的基类里面所以说我们可以自定义的修改一些鸭子的属性
package com.atguigu.strategy.improve;
/**
* @author: 德鑫
* Description:
* @Date: 2021/02/18
*/
public class Client {
public static void main(String[] args) {
WildDuck wildDuck = new WildDuck();
wildDuck.fly();//
ToyDuck toyDuck = new ToyDuck();
toyDuck.fly();
PekingDuck pekingDuck = new PekingDuck();
pekingDuck.fly();
pekingDuck.setFlyBehavior(new NoFlyBehavior());
System.out.println("北京鸭的实际飞行能力");
pekingDuck.fly();
toyDuck.quack();
System.out.println("修改之后玩具鸭的叫声");
toyDuck.setQuackBehavior(new GoodQuackBehavior());
toyDuck.quack();
}
}
三、策略模式的注意事项
1、对比策略模式和传统方法我们可以看到策略模式第一步就需要找出对象中变化的部分和不变的部分
2、策略模式的核心思想就是多用组合/聚合,少用继承
3、策略模式体现的也是ocp思想
3、提供了替代继承关系的方法
注意的问题。在我们定义策略组的时候没添加一个策略就需要添加一个类。这也是导致类爆炸的一个问题。
策略模式总体来看有一种使得程序变得比较庞大。对于不同的属性/功能在不同对象的表现上不同就需要定义一批针对该属性的类。
所以如何在项目中合理的使用策略模式来优化项目结构。对项目进行解耦需要针对特定的场景合理使用
ok~~ ,策略模式就聊到这里。
标签:策略,void,Gof,System,模式,鸭子,println,public,out 来源: https://blog.csdn.net/qq_42963930/article/details/113887788