小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
大家好,我是
方圆,这篇博客儿主要参考《Head First 设计模式》
1. 我遇到了一个问题
我有一只小鸭子,每天就知道嘎嘎叫,我觉得很无聊,我想让它学学飞,以下是对我的鸭子的代码
public class RealDuck extends Duck {
@Override
public void quack() {
super.quack();
}
}
我们也顺便看以下,它继承的基类Duck
public abstract class Duck {
public void quack(){
System.out.println("嘎嘎嘎");
}
}
1.1 我要让它怎么实现飞起来呢?
- 首先,我想到了!我直接在
基类Duck里写一个飞的方法不就好了吗?简单!
public abstract class Duck {
public void quack(){
System.out.println("嘎嘎嘎");
}
public void fly(){
System.out.println("我学会飞啦!");
}
}
简单测试一下
public class Test {
public static void main(String[] args) {
Duck myDuck = new RealDuck();
myDuck.quack();
myDuck.fly();
}
}

很好,问题貌似解决了,但是,如果是玩具小黄鸭实现了这个基类,那岂不是玩具鸭子也飞了起来!
public class Test {
public static void main(String[] args) {
Duck myDuck = new RealDuck();
myDuck.quack();
myDuck.fly();
System.out.println("玩具鸭 ↓");
Duck toyDuck = new ToyDuck();
toyDuck.fly();
}
}

这下可咋好?玩具鸭也飞起来了,那我在玩具鸭里把这个fly方法重写一下吧,这就解决了
public class ToyDuck extends Duck {
@Override
public void fly() {
System.out.println("我是玩具鸭,我不会飞");
}
}
但是回过头来,想想,我不光只有玩具鸭啊,我还有宠物鸭,唐老鸭,小黄鸭等等,很多鸭子都不会飞,每个类都要重写一下,岂不是很麻烦吗?而且代码很多都是重复的,这个问题怎么解决呀?
1.2 我想到了解决办法
- 设计原则:将应用中可能需要变化的部分,独立出来,不要和那些不变的代码混在一起。
那我们,把fiy()这个方法拿出来吧,但是要怎么往外拿呢?我们看一下下一个设计原则
- 设计原则:针对接口编程,而不是针对实现编程
怎么理解呢,拿鸭子飞这个例子来说,我们把飞定义为FlyBehavior接口,这样用它的实现类实现这个接口,以达到不同的飞的方式(会飞与不会飞),理解了吗?没有理解正常,我说的不清楚,看下面代码就明白了
public interface FlyBehavior {
void fyl();
}
public class CanFly implements FlyBehavior {
@Override
public void fyl() {
System.out.println("我能飞");
}
}
public class CantFly implements FlyBehavior {
@Override
public void fyl() {
System.out.println("我不会飞哇!");
}
}
两个实现类实现了FlyBehavior接口,成就了两种会飞与不会飞的方法,这样,这个飞行的动作就能够让其他的对象复用,因为这些行为已经跟鸭子没有关系了,实现了解耦,就算我们新增别的行为,也不需要修改鸭子的代码。
1.3 将这种方法进行实现
我们在Duck中引入FlyBehavior接口这个实例变量,如下
public abstract class Duck {
private FlyBehavior flyBehavior;
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void quack(){
System.out.println("嘎嘎嘎");
}
public void fly(){
flyBehavior.fyl();
}
}
这样我们就可以,根据不同的鸭子注入不同的行为,实现不同的动作啦,我们试试!
public class Test {
public static void main(String[] args) {
Duck myDuck = new RealDuck();
myDuck.setFlyBehavior(new CanFly());
myDuck.fly();
System.out.println("玩具鸭 ↓");
Duck toyDuck = new ToyDuck();
toyDuck.setFlyBehavior(new CantFly());
toyDuck.fly();
}
}

我们完成了鸭子业务的设计,我们回过头来,俯瞰一下这个大局

这也体现了一种设计原则
- 设计原则:多用组装,少用继承
等等,听你讲了这么半天?策略模式呢?啊?听了半天鸭子没有设计模式我不干!

等等!放下刀,我这就说,这就说!
2. 策略模式
其实策略模式,已经出现过了,只不过小的没提而已。我们看一眼它的描述,说的是啥?
- 策略模式:它定义了算法族,分别封装起来,让它们之间可以互换,此模式让算法的变化独立于使用算法的客户端。
明白了吧,好了,收!

好吧,把刀放下,我接着讲,接着讲昂!

认真看看红框里的东西,比对一下概念,是不是有点儿明白了? 咱说白了,它不就是,不就是能够在行为间不同的切换嘛? 我写写代码你就一下懂了!
写俩新接口实现类
public class FlyStyleOne implements FlyBehavior {
@Override
public void fyl() {
System.out.println("我先慢点儿飞!");
}
}
public class FlyStyleTwo implements FlyBehavior {
@Override
public void fyl() {
System.out.println("我再快点儿飞!");
}
}
测试一下
public class Test {
public static void main(String[] args) {
Duck myDuck = new RealDuck();
myDuck.setFlyBehavior(new CanFly());
myDuck.fly();
myDuck.setFlyBehavior(new FlyStyleOne());
myDuck.fly();
myDuck.setFlyBehavior(new FlyStyleTwo());
myDuck.fly();
}
}
显示结果

飞的不同的方式,对应的就是不同的算法,我能够把这些算法之间随便换,也就是我的鸭子,随便飞,想咋飞咋飞,换着法儿的飞!这就实现了策略模式。前边的都是铺垫,策略模式就这儿点儿。
Ok,这下行了吧?

能看到这里,也奖励一把小fafa吧~