设计模式

Head First 设计模式

感受

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

第一招 策略模式

1.1 设计原则

  1. 找出应用中可能需要变化之处,把它们独立出来,不要和哪些不需要变化的代码混在一起。
  2. 针对接口编程,而不是针对实现编程。
  3. 多用组合,少用继承。

1.2 上🦆UML

DuckUML.pngDuckUML.png

1.3 上🦆代码

封装飞行行为

interface FlyBehavior {
    void fly();
}

public class FlyWithWings implements FlyBehavior {
    public void fly() {
        System.out.println("鸭子的飞行了");
    }
}

public class FlyNoWay implements FlyBehavior {
    public void fly() {
        System.out.println("鸭子不会飞");
    }
}
language-Java

封装呱呱叫行为

interface QuackBehavior {
    void quack();
}

public class Qucak implements QuackBehavior {
    public void quack() {
        System.out.println("鸭子呱呱叫");
    }
}

public class Squeak implements QuackBehavior {
    public void quack() {
        System.out.println("鸭子吱吱叫");
    }
}

public class MuteQuack implements QuackBehavior {
    public void quack() {
        System.out.println("不会叫");
    }
}
language-Java

客户使用封装好的飞行和呱呱叫算法族

public abstract class Duck{
    private FlyBehavior flyBehavior;
    private QuackBehavior quackBehavior;

    public void swim() {
        System.out.println("鸭子会游泳");
    }

    public abstract void display();

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

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

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

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

public class MallardDuck extends Duck {
    public void display() {
        System.out.println("gree duck");
    }
}
language-Java

Test类

public class StrategymodeTest {
    public static void main(String [] args) {
        Duck d1 = new MallardDuck();
        d1.setFlyBehavior(new FlyWithWings());
        d1.performFly();
        d1.setQuackBehavior(new Qucak());
        d1.performQuack();
    }
}
language-Java

输入结果

$ java StrategymodeTest
鸭子的飞行了
鸭子呱呱叫

第二招 观察者模式

2.1 设计原则

  1. 找出应用中可能需要变化之处,把它们独立出来,不要和哪些不需要变化的代码混在一起。
  2. 针对接口编程,而不是针对实现编程。
  3. 多用组合,少用继承。
  4. 为交互对象之间的松耦合设计而努力

2.2 上UML图

观察者模式.png

观察者模式.png


2.3 上代码

  1. 主题和观察者的接口
// 主题接口
interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObserver();
}
// 观察者接口
interface Observer {
    void update(Subject o, Object arg);
}
language-Java
  1. 具体主题1
import java.util.ArrayList;

public class ConcreteSubject1 implements Subject{
    private ArrayList<Observer> observers;
    private ArrayList<String> arg;
    private boolean changed = false;

    public ConcreteSubject1() {
        observers = new ArrayList<Observer>();
        arg = new ArrayList<String>();
    }

    public void registerObserver(Observer o) {
        observers.add(o);
    }
    public void removeObserver(Observer o) {
        observers.remove(o);
    }
    public void notifyObserver() {
        if (changed) {
            for (int i = 0; i < observers.size(); i++) {
                Observer observer = (Observer)observers.get(i);
                observer.update(this, arg);
            }
            changed = false;
        }
    }

    protected void setChanged() {
        changed = true;
    }
    public void setMeasurements(String data) {
        arg.add(data);
        notifyObserver();
    }
}
language-Java
  1. 具体主题2
import java.util.ArrayList;

public class ConcreteSubject2 implements Subject{
    private ArrayList<Observer> observers;
    private ArrayList<String> arg;
    private boolean changed = false;

    public ConcreteSubject2() {
        observers = new ArrayList<Observer>();
        arg = new ArrayList<String>();
    }

    public void registerObserver(Observer o) {
        observers.add(o);
    }
    public void removeObserver(Observer o) {
        observers.remove(o);
    }
    public void notifyObserver() {
        if (changed) {
            for (int i = 0; i < observers.size(); i++) {
                Observer observer = (Observer)observers.get(i);
                observer.update(this, arg);
            }
        }
    }

    protected void setChanged() {
        changed = true;
    }
    public void setMeasurements(String data) {
        arg.add(data);
        notifyObserver();
    }
}
language-Java
  1. 关注具体主题1的具体观察者1
public class ConcreteObserver1 implements Observer {
    private Subject subject;

    public ConcreteObserver1(Subject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    public void update(Subject o, Object arg) {
        System.out.println("我是观察者1,我的主题1更新了");
    } 
}
language-Java
  1. 关注具体主题1,2的具体观察者2
public class ConcreteObserver2 implements Observer {
    private Subject subject1;
    private Subject subject2;

    public ConcreteObserver2(Subject subject1, Subject subject2) {
        this.subject1 = (Subject)subject1;
        this.subject2 = (Subject)subject2;
        subject1.registerObserver(this);
        subject2.registerObserver(this);
    }

    public void update(Subject o, Object arg) {
        if (o instanceof ConcreteSubject1) {
            System.out.println("我是观察者2,我的主题1更新了");
        }
        if (o instanceof ConcreteSubject2) {
            System.out.println("我是观察者2,我的主题2更新了");
        }
    }
}
language-Java
  1. 关注具体主题2的具体观察者3
public class ConcreteObserver3 implements Observer {
    private Subject subject;

    public ConcreteObserver3(Subject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    public void update(Subject o, Object arg) {
        System.out.println("我是观察者3, 我的主题2更新了");
    }
}
language-Java
  1. 测试代码
import java.util.ArrayList;

public class ObserverTest {
    public static void main(String[] args) {
        ConcreteSubject1 subject1 = new ConcreteSubject1();
        ConcreteSubject2 subject2 = new ConcreteSubject2();

        new ConcreteObserver1(subject1);
        new ConcreteObserver2(subject1, subject2);
        new ConcreteObserver3(subject2);
        subject1.setChanged();
        subject1.setMeasurements("test");
        subject2.setMeasurements("test2");
    }
}
language-Java
  1. 测试结果
$ java ObserverTest
我是观察者1,我的主题1更新了
我是观察者2,我的主题1更新了
我是观察者2,我的主题2更新了
我是观察者3, 我的主题2更新了
  1. java.util包实现了Observable类,也可以满足一些观察者的情况。首先,因为没有Observer接口,所以无法建立自己的实现,和Java内置的Observer API搭配使用。

第3招 装饰者模式

装饰纸模式:动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。


3.1设计原则

  1. 封装变化
  2. 多用组合,少用继承
  3. 针对接口编程,不针对实现编程
  4. 为交互对象之间的松耦合设计而努力
  5. 对扩展开发,对修改关闭

3.2上UML图

先决定那种咖啡,在决定使用什么配料。

装饰者模式.png

装饰者模式.png


3.3上代码

  1. 定义饮料类,必须设置一个抽象方法。
public abstract class Beverage {
    String description = "Unknown Beverage";
    public String getDescription() {
        return description;
    }
    public abstract double cost();
}
language-Java

  1. 深烘咖啡,实现夫类的抽象方法。
public class DarkRoast extends Beverage {
    public DarkRoast() {
        description = "DarkRoast Coffee";
    }
    public double cost() {
        return 1.19;
    }
}
language-Java

  1. 定义装饰者。调味装饰者
public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}
language-Java

  1. 实现第一个一个装饰者。牛奶配料
public class Milk extends CondimentDecorator{
    Beverage beverage;
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }
    public String getDescription() {
        return beverage.getDescription() + ", Milk";
    }
    public double cost() {
        return .10 + beverage.cost();
    }
}
language-Java

  1. 实现第二个装饰者。摩卡配料
public class Mocha extends CondimentDecorator {
    Beverage beverage;
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }
    public double cost() {
        return .20 + beverage.cost();
    }
}
language-Java

  1. 测试代码
public class StarbuzzCoffee {
    public static void main(String[] args) {
        // 没有配料的拿铁咖啡
        Beverage beverage = new DarkRoast();
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
        // 摩卡, 牛奶, 拿铁咖啡(DarkRoast)
        Beverage beverage2 = new DarkRoast();
        beverage2 = new Mocha(beverage2);
        beverage2 = new Milk(beverage2);
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
    }
}
language-Java

  1. 运行结果
java StarbuzzCoffee
DarkRoast Coffee $1.19
DarkRoast Coffee, Mocha, Milk $1.49

第四招 工厂模式

工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

4.1设计原则

  1. 多用组合,少用继承
  2. 针对接口编程,不针对实现编程
  3. 为交互对象之间的松耦合设计而努力
  4. 类应该对扩展开放,对修改关闭
  5. 依赖抽象,不要依赖具体类。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 hjxstart@126.com