【HeadFirst系列之HeadFirst设计模式】第2天之设计模式入门之策略设计模式

Scroll Down

前言

欢迎来到设计模式世界
从今日起,陆续分享《HeadFirst设计模式》的读书笔记,希望能够帮助大家更好的理解设计模式,提高自己的编程能力。

设计模式本质上就是前人比较成熟的经验和智慧。他们遇到过相同的问题,也顺利地解决了这些问题。

跟随前人的脚步,可以少走弯路,也可以站在巨人的肩膀上看得更远。

使用模式最好的方式是:"把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。"以往是代码复用,现在是经验复用。

今天要分享的是【设计模式入门之策略设计模式】,希望对大家有所帮助。

设计模式入门之策略设计模式

书籍精彩内容

  • 模拟鸭子
    先从简单的模拟鸭子应用做起

  • 让鸭子飞
    让鸭子飞

  • 出问题了:橡皮鸭也会飞了
    橡皮鸭也会飞了

    对代码所做的局部修改,影响层面可不只是局部(会飞的橡皮鸭)。

  • 继承解决
    橡皮鸭会飞之继承解决法

    弊端: 希望以后每六个月更新产品(至于更新的方法,他们还没想到)。Joe知道规格会常常改变,每当有新的鸭子子类出现,他就要被迫检查并可能需要覆盖fly()和quark()…这简直是无穷无尽的噩梦。

  • 接口解决
    橡皮鸭会飞之接口解决法

    弊端:重复代码变多,历史所有子类都得修改。

  • 你怎么解决问题
    你怎么解决橡皮鸭会飞问题

  • 软件开发真理
    软件开发不变的真理

  • 归零
    橡皮鸭会飞问题归零
    橡皮鸭会飞问题归零1

  • 设计鸭子的行为
    设计鸭子的行为

  • 针对接口编程
    针对接口编程

  • 实现鸭子的行为
    实现鸭子的行为

  • 整合鸭子的行为
    整合鸭子的行为1
    整合鸭子的行为2
    整合鸭子的行为3

  • 鸭子行为测试
    鸭子行为测试1
    鸭子行为测试2

  • 动态设定行为
    动态设定行为1
    动态设定行为2

  • 封装行为的大局观
    分装行为的大局观1
    分装行为的大局观2

  • 设计模式
    策略设计模式定义

    • 如何使用设计模式
      如何使用策略设计模式
    • 为何要使用设计模式
      为何使用策略设计模式1
      为何使用策略设计模式2

代码

  • 第一版(出问题:橡皮鸭会飞)
/**
 * 鸭子超类
 */
public abstract class Duck {
    /**
     * 呱呱叫
     */
    public void quack() {
        System.out.println("呱呱叫");
    }

    /**
     * 游泳
     */
    public void swim() {
        System.out.println("游泳");
    }

    /**
     * 鸭子外观
     */
    abstract void display();

    /**
     * 鸭子其他方法...
     *  todo
     */

    /**
     * 飞行
     */
    public void fly() {
        System.out.println("飞行");
    }

}
public class MallardDuck extends Duck {
    @Override
    public void display() {
        System.out.println("我的外观是绿头");
    }
}
public class RedheadDuck extends Duck {
    @Override
    public void display() {
        System.out.println("我的外观是红头");
    }
}
public class RubberDuck extends Duck {
    @Override
    public void display() {
        System.out.println("我的外观是橡皮");
    }

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

    @Override
    public void fly() {
        // 什么都不做,不会飞
    }
}
public class DecoyDuck extends Duck {
    @Override
    public void display() {
        System.out.println("我的外观是诱饵");
    }

    @Override
    public void quack() {
        // 什么都不做,不会叫
    }

    @Override
    public void fly() {
        // 什么都不做,不会飞
    }
}
public class RubberDuckTest {

    @Test
    public void display() {
        RubberDuck rubberDuck = new RubberDuck();
        rubberDuck.quack();//见鬼了:橡皮鸭也会叫了
        //解决:覆盖超类方法为吱吱叫
    }
}
  • 第二版:继承和接口解决
public interface Flyable {
    void fly();
}
public interface Quackable {
    void quack();
}
public abstract class Duck {
    public void swim() {
        System.out.println("游泳");
    }

    abstract public void display();
}
public class MallardDuck extends Duck implements Flyable, Quackable {
    @Override
    public void display() {
        System.out.println("我的外观是绿头");
    }

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

    @Override
    public void quack() {
        System.out.println("嘎嘎叫");
    }
}
public class RedheadDuck extends Duck implements Flyable, Quackable {
    @Override
    public void display() {
        System.out.println("我的外观是红头");
    }

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

    @Override
    public void quack() {
        System.out.println("嘎嘎叫");
    }
}
public class RubberDuck extends Duck implements Quackable {
    @Override
    public void display() {
        System.out.println("外观是橡皮鸭");
    }

    @Override
    public void quack() {
        System.out.println("吱吱叫");
    }
}
public class DecoyDuck extends Duck {
    @Override
    public void display() {
        System.out.println("我的外观是诱饵");
    }
}
  • 第三版:策略设计模式解决(封装变化,代码灵活且耦合性低)
    面向实现编程,而不是面向接口编程
public abstract class Animal {
    abstract void makeSound();


}
public class AnimalFactory {
    public static Animal getAnimal(Animal animal) {
        if (animal instanceof Dog) {
            return new Dog();
        } else if (animal instanceof Cat) {
            return new Cat();
        }
        return null;
    }
}
public class Cat extends Animal {
    public void makeSound() {
        meow();
    }

    public void meow() {
        System.out.println("喵喵叫");
    }
}
public class Dog extends Animal {
    public void makeSound() {
        bark();
    }

    public void bark() {
        System.out.println("汪汪叫");
    }
}
public class AnimalTest {

    @Test
    public void makeSound() {
        //针对实现编程
        Dog dog = new Dog();
        dog.bark();
        //针对接口编程
        Animal animal = new Dog();
        animal.makeSound();
        Objects.requireNonNull(AnimalFactory.getAnimal(new Dog())).makeSound();
    }
}

第三版会飞的鸭子解决方案:

public interface FlyBehavior {
    void fly();
}
public class FlyNoWay implements FlyBehavior {
    public void fly() {
        System.out.println("I can't fly");
    }
}
public class FlyRocketPowered implements FlyBehavior {
    public void fly() {
        System.out.println("I'm flying with a rocket");
    }
}
public class FlyWithWings implements FlyBehavior {
    public void fly() {
        System.out.println("I'm flying!!");
    }
}
public interface QuackBehavior {
    void quack();
}
public class MuteQuack implements QuackBehavior {
    public void quack() {
        System.out.println("<< Silence >>");
    }
}
public class Quack implements QuackBehavior {
    public void quack() {
        System.out.println("Quack");
    }
}
public class Squeak implements QuackBehavior {
    public void quack() {
        System.out.println("Squeak");
    }
}
public abstract class Duck {
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;

    public void setFlyBehavior(FlyBehavior fb) {
        this.flyBehavior = fb;
    }

    public void setQuackBehavior(QuackBehavior qb) {
        this.quackBehavior = qb;
    }

    public void swim() {
        System.out.println("All ducks float, even decoys");
    }

    public abstract void display();

    public void performFly() {
        flyBehavior.fly();
    }

    public void performQuack() {
        quackBehavior.quack();
    }

}

public class MallardDuck extends Duck {
    public MallardDuck() {
        flyBehavior = new FlyWithWings();
        quackBehavior = new Quack();
    }

    public void display() {
        System.out.println("I'm a real Mallard duck");
    }
}

public class ModelDuck extends Duck {
    public ModelDuck() {
        flyBehavior = new FlyNoWay();
        quackBehavior = new Quack();
    }

    public void display() {
        System.out.println("I'm a model duck");
    }
}
public class MiniDuckSimulator {
    public static void main(String[] args) {
        MallardDuck mallard = new MallardDuck();
        mallard.performFly();
        mallard.performQuack();
        ModelDuck model = new ModelDuck();
        model.performFly();
        model.setFlyBehavior(new FlyRocketPowered());
        model.performFly();
    }
}

图例

  • 会飞的鸭子第一版
    会飞的鸭子第一版1
    会飞的鸭子第一版2
    会飞的鸭子第一版3
  • 会飞的鸭子第二版
    会飞的鸭子第二版1
    会飞的鸭子第二版2
  • 会飞的鸭子第三版
    会飞的鸭子第三版1
    会飞的鸭子第三版2
    会飞的鸭子第三版3
    会飞的鸭子第三版4
    会飞的鸭子第三版5

术语

  • OO:Object Oriented(面向对象)
  • 超类:superclass
  • 子类:subclass
  • 模拟:simulate,软件可以模拟现实世界,比如会飞的鸭,网购等
  • 类图:可以展示类之间的关系,比如继承、实现、依赖等
  • 复用:reuse

工具箱

策略设计模式工具箱

茶话会

彩蛋1
彩蛋2

收获

1.如何查看超类实现

ctrl+h

2.uml类图如何画

1)idea自动生成

https://blog.csdn.net/qq_52302333/article/details/131341626
非社区版的,diagrams自带就有该功能,社区版需要安装插件

plantUML:https://plantuml.com/zh/

simpleUML:https://cloud.tencent.com/developer/article/2428172 【无插件,需要离线安装】
2)手绘

通过starUML

3.brew查看安装软件位置

brew info graphviz

4.查看mac隐藏文件夹

command+shift+.

5.软件迭代的原则:对现有功能影响降低到最小,最好不影响

知识点回顾与总结

  • 1.会飞的鸭子问题解决方案演进
  • 2.策略设计模式的介绍
  • 3.一些OO原则:
    • 封装变化
    • 多用组合,少用继承(I have a 而不是I’m a)
    • 针对接口编程,不针对实现编程

策略设计模式相关源码

策略设计模式源码地址

HeadFirst设计模式在线版电子书

HeadFirst设计模式在线版电子书