设计模式之策略模式
2023-03-14 09:48:36 时间
情景:
要设计很多鸭子,每个鸭子都有quack(呱呱叫)和swim功能。
可以设计一个Duck类,含有quack()和swim()方法就可以了。具体鸭子类继承Duck类。
新需求:要求添加fly功能。
如果直接给Duck添加fly()方法,会出现问题,因为有一部分鸭子是不会飞的。
选择创建Flyable接口,只有会飞的鸭子才继承接口,可以解决这一问题,但是造成代码无法复用。
设计原则:封装变化
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
因为鸭子的行为是变化的所以把鸭子的行为封装起来,创建一组行为类。
设计原则:针对接口编程,而不是针对实现编程。
针对接口编程的意思是: Animal animal = new Dog(); 而不是 Dog dog = new Dog();
Animal可以是超类或者接口,主要是通过多态,使得代码容易被扩展。
为每个行为写一个接口,行为的具体实现就是接口的一个实现类。这样具体行为就可以容易的被修改。
行为接口:
public interface FlyBehavior { public void fly(); } ----------- public interface QuackBehavior { void quack(); }
实现行为的具体类:
public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("I can't fly"); } } …………………… public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("I'm flying!"); } } …………………… public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("Quack"); } } …………………… public class MuteQuack implements QuackBehavior { @Override public void quack() { System.out.println("<< Silence >>"); } }
Duck超类:
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { }public void performFly() { flyBehavior.fly(); // 委托给行为类 } public void performQuack() { quackBehavior.quack(); } public void swim() { System.out.println("All ducks flost, even decoys!"); } public void display() { System.out.println("I am a duck."); } }
Duck一个具体实现类:
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display() { System.out.println("I'm a real Mallard duck."); } }
测试类:
public class MiniDuckSimulator { public static void main(String[] args) { Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly(); } }
输出:
Quack
I'm flying!
如果能在Duck类中通过setter动态设置行为,而不是只能在构造方法中绑定,就可以更灵活的改变鸭子的行为。
Duck类:
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { } public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } //...... }
新建一个模型鸭类型,默认不会飞
public class ModelDuck extends Duck { public ModelDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new Quack(); } public void display() { System.out.println("I am a model duck."); } }
然后建立一个火箭动力类(???)
public class FlyRocketPowered implements FlyBehavior { @Override public void fly() { System.out.println("I am flying with a rocket."); } }
通过动态改变行为,模型鸭就可以飞啦~~
public class MiniDuckSimulator { public static void main(String[] args) { Duck model = new ModelDuck(); model.performFly(); model.setFlyBehavior(new FlyRocketPowered()); model.performFly(); } }
输出:
I can't fly I am flying with a rocket.
把鸭子的行为封装起来,这样可以自由的改变鸭子的行为,也方便对行为的扩展。
把行为改变为算法,就是策略模式。
设计原则:多用组合,少用继承。
策略模式:定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于算法的客户。
类图:
(讲道理我觉得书上这个例子举得一点都不好。。。。)
一个简单的例子:
public interface Strategy { public int doOperator(int num1, int num2); } …………………… public class AddStrategy implements Strategy { @Override public int doOperator(int num1, int num2) { return num1 + num2; } } …………………… public class SubStrategy implements Strategy { @Override public int doOperator(int num1, int num2) { return num1 - num2; } } …………………… public class MulStrategy implements Strategy { @Override public int doOperator(int num1, int num2) { return num1 * num2; } } …………………… public class Context { Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } public int doOperator(int num1, int num2) { return strategy.doOperator(num1, num2); } }
测试类:
public class Main { public static void main(String[] args) { Context context = new Context(new AddStrategy()); System.out.println(context.doOperator(2, 3)); context.setStrategy(new SubStrategy()); System.out.println(context.doOperator(2, 3)); context.setStrategy(new MulStrategy()); System.out.println(context.doOperator(2, 3)); } } /* Output: 5 -1 6 */
相关文章
- 在 Go 里用 CGO?这 7 个问题你要关注!
- 9款优秀的去中心化通讯软件 Matrix 的客户端
- 求职数据分析,项目经验该怎么写
- 在OKR中,我看到了数据驱动业务的未来
- 火山引擎云原生大数据在金融行业的实践
- OpenHarmony富设备移植指南(二)—从postmarketOS获取移植资源
- 《数据成熟度指数》报告:64%的企业领袖认为大多数员工“不懂数据”
- OpenHarmony 小型系统兼容性测试指南
- 肯睿中国(Cloudera):2023年企业数字战略三大趋势预测
- 适用于 Linux 的十大命令行游戏
- GNOME 截图工具的新旧截图方式
- System76 即将推出的 COSMIC 桌面正在酝酿大变化
- 2GB 内存 8GB 存储即可流畅运行,Windows 11 极致精简版系统 Tiny11 发布
- 迎接 ecode:一个即将推出的具有全新图形用户界面框架的现代、轻量级代码编辑器
- loongarch架构介绍(三)—地址翻译
- Go 语言怎么解决编译器错误“err is shadowed during return”?
- 敏捷:可能被开发人员遗忘的部分
- Denodo预测2023年数据管理和分析的未来
- 利用数据推动可持续发展
- 在 Vue3 中实现 React 原生 Hooks(useState、useEffect),深入理解 React Hooks 的