设计模式学习笔记

策略模式

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户

公司做了一个模拟鸭子的游戏,这些鸭子可以叫和游泳,现在想让这些鸭子飞

这里写图片描述
这样做会让橡皮鸭也具备飞的行为,虽然在fly()中可以不做任何动作,如果每次进来一个鸭子就覆盖方法,很不好,例如:诱饵鸭不会飞也不会叫,橡皮鸭不会飞也不会叫
这里写图片描述
将飞和叫的行为弄成接口会造成代码无法复用
这里写图片描述
把飞行和交的行为弄成接口,具体的叫法由类具体实现

public interface FlyBehavior {
    /*
     * 飞行行为接口
     */
    public void fly();
}
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 interface QuackBehavior {
    /*
     * 叫的行为接口
     */
    public void quack();
}
public class Quack implements QuackBehavior {

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

}
public class Squeak implements QuackBehavior{

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

}
public abstract class Duck {

    /*
     * 鸭子抽象类
     */
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
    public Duck() {};
    public abstract void displaly();
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }
    public void swim() {
        System.out.println("All ducks float");
    }
    //可以动态设置鸭子的行为
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

}
public class MallardDuck extends Duck{

    /*
     * 绿头鸭实现类
     */
    public MallardDuck() {
        quackBehavior = new Quack();
        flyBehavior = new FlyWithWings();
    }

    @Override
    public void displaly() {
        System.out.println("I'm a real Mallard duck");
    }
}
public class MiniDuckSimulator {

    /*
     * 测试类
     */
    public static void main(String[] args) {
        Duck mallard = new MallardDuck();
        //I'm flying
        mallard.performFly();
        //quack
        mallard.performQuack();
    }

}

加上一个模型鸭,使模型鸭可以动态改变行为,在后期使模型鸭具有火箭动力

public class FlyRocketPowered implements FlyBehavior {

    /*
     * 具有火箭动力的飞行
     */
    @Override
    public void fly() {
        System.out.println("I'm flying with a rocket");
    }

}
public class ModelDuck extends Duck {

    /*
     * 模型鸭
     */
    public ModelDuck() {
        flyBehavior = new FlyNoWay();
        quackBehavior = new Quack();
    }
    @Override
    public void displaly() {
        System.out.println("I'm a model duck");
    }

}
public class MiniDuckSimulator {

    /*
     * 测试类
     */
    public static void main(String[] args) {
        Duck mallard = new MallardDuck();
        //I'm flying
        mallard.performFly();
        //quack
        mallard.performQuack();
        Duck model = new ModelDuck();
        //I can't fly
        model.performFly();
        model.setFlyBehavior(new FlyRocketPowered());
        //I'm flying with a rocket
        model.performFly();
    }

}

观察者模式

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新

为了展示气象数据而封装了一个数据对象WeatherData,当气象数据更新的时候,所有布告板上的显示都得发生改变,这时系统调用WeaherData对象的measurementsChanged()方法,错误的示例如下:
这里写图片描述
定义观察者模式
这里写图片描述
最终的类图
这里写图片描述

public interface Subject {

    /*
     * 主题对象实现的接口
     */

    //注册观察者
    public void registerObserver(Observer o);
    //删除观察者
    public void removeObserver(Observer o);
    //当主题状态改变时,这个方法会被调用,以通知所有的的观察者
    public void notifyObservers();
}
public interface Observer {

    /*
     * 观察者对象实现的接口
     */
    public void update(float temp, float humidity, float pressure);
}
public interface DisplayElement {

    /*
     * 展示行为的接口
     */
    public void display();
}

实现气象数据对象

public class WeatherData implements Subject{

    private ArrayList observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    @Override
    public void notifyObservers() {
        for (int i=0; i<observers.size(); i++) {
            Observer observer = (Observer)observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

实现布告板

public class CurrentConditionsDisplay implements Observer, DisplayElement{

    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }
}

测试类

public class WeatherStation {

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        //Current conditions: 80.0F degrees and 65.0% humidity
        weatherData.setMeasurements(80, 65, 30.4f);
    }
}

装饰者模式

装饰者模式动态的将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择,可以在不修改底层代码的情况下,给对象赋予新的职责

咖啡店的类设计原来是这样的
这里写图片描述
但是顾客会要求加入各种调料,如蒸奶(Steamed Milk),豆浆(Soy)
这里写图片描述
用父类计算调料的价钱,子类计算饮料的价钱
这里写图片描述
哪些需求或因素改变时会影响这个设计
这里写图片描述
以装饰者构造饮料订单
这里写图片描述

装饰者模式动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案

这里写图片描述

public abstract class Beverage {

    /*
     * Beverage类
     */
    String description = "Unknown Beverage";
    public String getDescription() {
        return description;
    }
    public abstract double cost();
}
public abstract class CondimentDecorator extends Beverage{

    /*
     * 调料装饰抽象类
     */
    @Override
    public abstract String getDescription();
}
public class Espresso extends Beverage {

    /*
     * 浓缩咖啡类
     */
    public Espresso() {
        description = "Espresso";
    }
    @Override
    public double cost() {
        return 1.99;
    }

}
public class HouseBlend extends Beverage {

    /*
     * 另一种咖啡类
     */
    public HouseBlend() {
        description = "House Blend Coffee";
    }
    @Override
    public double cost() {
        return 0.89;
    }

}

已经有了抽象组件(Beverage),具体组件(HouseBlend),抽象装饰者(CondimentDecorator),下面实现具体装饰者

public class Mocha extends CondimentDecorator {

    /*
     * 摩卡装饰者
     */
    Beverage beverage;
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }

    @Override
    public double cost() {
        return 0.20 + beverage.cost();
    }

}
public class Whip extends CondimentDecorator {

    /*
     * 奶油装饰者
     */
    Beverage beverage;
    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Whip";
    }
    @Override
    public double cost() {
        return 0.58 + beverage.cost();
    }

}
public class StarBuzzCoffee {

    public static void main(String[] args) {

        /*
         * 测试类
         */
        Beverage beverage = new Espresso();
        //Espresso $1.99
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
        Beverage beverage2 = new HouseBlend();
        beverage2 = new Mocha(beverage2);
        beverage2 = new Mocha(beverage2);
        beverage2 = new Whip(beverage2);
        //House Blend Coffee, Mocha, Mocha, Whip $1.87
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
    }

}

这里写图片描述
装饰Java io类
这里写图片描述
test.txt

This Is Just For Test
public class LowerCaseInputStream extends FilterInputStream {

    /*
     * 自己的装饰类,将大写字母转为小写字母
     */
    protected LowerCaseInputStream(InputStream in) {
        super(in);
    }

    @Override
    public int read() throws IOException {
        int c = super.read();
        return (c == -1 ? -1 : Character.toLowerCase((char)c));
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int result = super.read(b, off, len);
        for (int i=off; i<=off+result; i++) {
            b[i] = (byte)Character.toLowerCase((char)b[i]);
        }
        return result;
    }
}
public class InputTest {

    public static void main(String[] args) {

        /*
         * 测试自己的装饰类
         */
        int c;
        try {
            InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
            while ((c = in.read()) >= 0) {
                //this is just for test
                System.out.print((char)c);
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

工厂模式

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

有订购披萨的工具如下
这里写图片描述
当披萨菜单发生改变时,代码必须进行修改。我们可以把创建对象移到orderPizza()之外,如下所示
这里写图片描述

public abstract class Pizza {

    /*
     * 披萨类
     */

    String name;
    //面团
    String dough;
    //酱
    String sauce;
    //糕点上的装饰配料
    ArrayList toppings = new ArrayList();

    void prepare() {
        System.out.println("Preparing " + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding sauce...");
        System.out.println("Adding toppings : ");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.println(" " + toppings.get(i));
        }
    }

    //烤
    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }

    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    String getName() {
        return name;
    }
}
public class NYStyleCheesePizza extends Pizza{

    /*
     * 纽约风味的芝士披萨类
     */
    public NYStyleCheesePizza() {
        //大蒜番茄酱和薄饼
        name = "NY Style Sauce and Chees Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Cheese");
    }
}
public class ChicagoStyleCheesePizza extends Pizza {

    /*
     * 芝加哥风味的芝士披萨
     */
    public ChicagoStyleCheesePizza() {
        //小番茄厚饼
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
        toppings.add("Shredded Mozzarella Cheese");
    }

    void cut() {
        //覆盖了cut()方法,将披萨切成正方形
        System.out.println("Cutting the pizza into square slices");
    }
}
public abstract class PizzaStore {

    /*
     * 披萨店的抽象类
     */
    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    //工厂方法是抽象的
    protected abstract Pizza createPizza(String type);
}
public class NYPizzaStore extends PizzaStore{

    /*
     * 纽约风味的披萨店
     */
    @Override
    protected Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new NYStyleCheesePizza();
        } else if (type.equals("veggie")) {
            //没有写这个类,只是举一个例子,动态的创建类
            //return new NYStyleVeggiePizza();
        }
        return null;
    }
}
public class ChicagoPizzaStore extends PizzaStore{

    /*
     * 芝加哥风味的披萨店
     */
    @Override
    protected Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new ChicagoStyleCheesePizza();
        } else if (type.equals("veggie")) {
            //根据要求动态创建类
            //return new ChicagoStyleVeggiePizza();
        }
        return null;
    }
}

测试类

public class PizzaTestDrive {

    public static void main(String[] args) {

        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();
        /*Preparing NY Style Sauce and Chees Pizza
        Tossing dough...
        Adding sauce...
        Adding toppings :
        Grated Reggiano Cheese
        Bake for 25 minutes at 350
        Cutting the pizza into diagonal slices
        Place pizza in official PizzaStore box*/
        Pizza pizza = nyStore.orderPizza("cheese");
        //order a NY Style Sauce and Chees Pizza
        System.out.println("order a " + pizza.getName() + "\n");

        /*Preparing Chicago Style Deep Dish Cheese Pizza
        Tossing dough...
        Adding sauce...
        Adding toppings :
        Shredded Mozzarella Cheese
        Bake for 25 minutes at 350
        Cutting the pizza into square slices
        Place pizza in official PizzaStore box*/
        pizza = chicagoStore.orderPizza("cheese");
        //order a Chicago Style Deep Dish Cheese Pizza
        System.out.println("order a " + pizza.getName() + "\n");
    }
}

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

现在,我们要建造一个工厂来生产原料,这个工厂负责创建原料家族中的每一种原料,因为每个地区所需要的原料是不同的

public interface PizzaIngredientFactory {

    /*
     * 披萨原料工厂的抽象类
     */
    //面团
    public Dough createDough();
    //酱
    public Sauce createSauce();
    //奶酪
    public Cheese createCheese();
    //蔬菜
    public Veggies[] createVeggies();
    //意大利辣味香肠
    public Pepperoni createPepperoni();
    //蛤
    public Clams createClam();
}
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{

    /*
     * 纽约披萨原料工厂类
     */
    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

    @Override
    public Veggies[] createVeggies() {
        //里面的原料实现Veggies的接口类
        Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
        return veggies;
    }

    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }

    @Override
    public Clams createClam() {
        return new FreshClams();
    }
}
public abstract class Pizza {

    /*
     * 修改后的披萨类
     */
    String name;
    //可以将dough弄为一个接口,让具体的类实现它
    Dough dough;
    //同理将sauce弄为一个接口
    Sauce sauce;
    //将veggies弄为一个接口
    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clam;

    //把prepare方法声明成抽象。在这个方法中,我们需要收集披萨所需的原料,而这些原料当然是来自原料工厂了
    abstract void prepare();

    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }

    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    void setName(String name) {
        this.name = name;
    }

    String getName() {
        return name;
    }
}
public class CheesePizza extends Pizza{

    PizzaIngredientFactory ingredientFactory;

    public CheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }
    @Override
    void prepare() {
        System.out.println("Preparing " + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}
public class NYPizzaStore extends PizzaStore {

    /*
     * 修改后的纽约风味的披萨店
     */
    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory =
                new NYPizzaIngredientFactory();

        if (type.equals("cheese")) {

            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese Pizza");

        } else if (type.equals("veggie")) {

            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggie Pizza");

        } else if (type.equals("clam")) {

            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam Pizza");

        }
        return pizza;
    }
}

看类图了解关系

这里写图片描述

从PizzaStore的观点来看

这里写图片描述

单例模式

单例模式确保一个类只有一个实例,并提供全局访问点

经典的单例模式实现

public class Singleton {

    //独特的实例
    private static Singleton uniqueInstance;
    //私有化构造函数,这样就不能通过new来创建这个对象
    private Singleton() {}
    //声明为静态方法,这样就可通过Singleton.getInstance()方法来获得Singleton对象
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }

}

如果是多线程则会造成问题,解决方法一

public static synchronized Singleton getInstance() {
    if (uniqueInstance == null) {
        uniqueInstance = new Singleton();
    }
    return uniqueInstance;
}

这样会对性能造成问题,解决方法二

public class Singleton {
    private static Singleton uniqueInstance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return uniqueInstance;
    }

}

加载类时直接创建,解决方法三

public class Singleton {

    //volatile关键字确保,当uniqueInstance变量被初始化成Singleton实例时,
    //多个线程正确地处理uniqueInstance变量
    private volatile static Singleton uniqueInstance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }

}

命令模式

命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作

有一个遥控器,有7个插槽,每个插槽有开和关2个按钮用来操作电器,类似如下实现是非常糟糕的,有新厂商进来就得修改代码

if (slot1 == Light) {
    light.on()
} else if (slot1 = TV) {
    tv.on()
}

一种借鉴的思路是去餐厅吃饭,服务员把你想吃的东西写到菜单上,然后把菜单给了厨师,厨师按照菜单做就行,而不是让服务员直接告诉厨师应该做哪些东西,先写一个简单的Demo

public interface Command {

    /*
     * 命令接口
     */
    public void execute();
}
public class Light {

    /*
     * 灯类
     */
    public Light() {
    }

    public void on() {
        System.out.println("Light is on");
    }

    public void off() {
        System.out.println("Light is off");
    }
}
public class LightOnCommand implements Command{

    /*
     * 打开灯的命令
     */
    Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }
    @Override
    public void execute() {
        light.on();
    }
}
public class SimpleRemoteControl {

    /*
     * 简单遥控器类
     */
    Command slot;

    public SimpleRemoteControl() {}

    public void setCommand(Command command) {
        slot = command;
    }

    public void buttonWasPressed() {
        slot.execute();
    }
}

测试类

public class RemoteControlTest {

    public static void main(String[] args) {
        SimpleRemoteControl remote = new SimpleRemoteControl();
        Light light = new Light();
        LightOnCommand lightOn  = new LightOnCommand(light);
        remote.setCommand(lightOn);
        //Light is on
        remote.buttonWasPressed();
    }
}

命令模式的作用:

  1. 队列请求–>日程安排,线程池,工作队列,想象有一个工作队列:你在某一端添加命令,然后另一端是线程。线程进行下面的动作:从嘟列中取出一个命令,调用它的execute()方法,等待这个调用完成,然后将此命令丢弃,再取出下一个命令,这样工作队列类和进行计算的对象之间是完全解耦的,此刻线程可能进行财务运算,下一刻却在读取网路数据。工作队列只知道取出命令对象,然后调用其execute()方法。
  2. 日志请求–>某些应用需要我们将所有的动作都记录在日志中,并能在系统死机之后,重新调用这些动作恢复到之前的状态

适配器模式

适配器模式将一个类的接口,装换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间

这里写图片描述
包装了鸭子适配器的火鸡

public interface Duck {

    /*
     * 鸭子接口
     */
    public void quack();
    public void fly();
}
public interface Turkey {

    /*
     * 火鸡接口
     */
    public void gobble();
    public void fly();
}
public class MallardDuck implements Duck {

    /*
     * 野鸭类
     */
    @Override
    public void quack() {
        System.out.println("Quack");
    }

    @Override
    public void fly() {
        System.out.println("I'm flying");
    }

}
public class WildTurkey implements Turkey {

    /*
     * 野生火鸡类
     */
    @Override
    public void gobble() {
        System.out.println("Gobble gobble");
    }

    @Override
    public void fly() {
        System.out.println("I'm flying a short distance");
    }

}
public class TurkeyAdapter implements Duck {

    /*
     * 适配器类
     */
    Turkey turkey;
    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }
    @Override
    public void quack() {
        turkey.gobble();
    }
    @Override
    public void fly() {
        //多飞几次模拟鸭子
        for (int i=0; i<3; i++)
            turkey.fly();
    }

}
public class DuckTest {

    /*
     * 测试类
     */
    public static void main(String[] args) {

        Duck duck = new MallardDuck();
        //Quack
        duck.quack();
        //I'm flying
        duck.fly();
        WildTurkey turkey = new WildTurkey();
        Duck turkeyAdapter = new TurkeyAdapter(turkey);
        //Gobble gobble
        turkeyAdapter.quack();
        //I'm flying a short distance
        //I'm flying a short distance
        //I'm flying a short distance
        turkeyAdapter.fly();
    }

}

类图
这里写图片描述

外观模式

外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用

当我们在家庭影院观看电影时,要做很多事情,如打开爆米花机,开始爆米花,将灯光调暗,放下屏幕等,我们可以通过实现一个提供更合理的接口的外观类,将一个复杂的子系统变得容易使用

public class HomeTheaterFacade {

    /*
     * 家庭影院外观类
     */
    Amplifier amp;
    Tuner tuner;
    DvdPlayer dvd;
    CdPlayer cd;
    Projector projector;
    TheaterLights lights;
    Screen screen;
    PopcornPopper popper;

    public HomeTheaterFacade(Amplifier amp,
                             Tuner tuner,
                             DvdPlayer dvd,
                             CdPlayer cd,
                             Projector projector,
                             Screen screen,
                             TheaterLights lights,
                             PopcornPopper popper) {

        this.amp = amp;
        this.tuner = tuner;
        this.dvd = dvd;
        this.cd = cd;
        this.projector = projector;
        this.screen = screen;
        this.lights = lights;
        this.popper = popper;
    }

    public void watchMovie(String movie) {
        System.out.println("Get ready to watch a movie...");
        popper.on();
        popper.pop();
        lights.dim(10);
        screen.down();
        projector.on();
        projector.wideScreenMode();
        amp.on();
        amp.setDvd(dvd);
        amp.setSurroundSound();
        amp.setVolume(5);
        dvd.on();
        dvd.play(movie);
    }


    public void endMovie() {
        System.out.println("Shutting movie theater down...");
        popper.off();
        lights.on();
        screen.up();
        projector.off();
        amp.off();
        dvd.stop();
        dvd.eject();
        dvd.off();
    }
}

当我们想看电影时,只要调用watchMovie()方法,关闭电影时只要调用endMovie()方法,省去了很多繁琐的操作

类图

这里写图片描述

模板方法模式

模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤

要开发咖啡和茶的冲泡方法,它们的过程如下:
这里写图片描述
刚开始我们想到的是抽取咖啡和茶
这里写图片描述
其中prepareRecipe()方法是包含四个方法的合集,接着我们对2步和第4步不同的部分进一步抽象,抽象出一个咖啡因饮料的类

public abstract class CaffeineBeverage {

    /*
     * 咖啡因饮料是一个抽象类
     */
    //不希望子类覆盖这个方法,并且将步骤2和步骤4泛化为brew()和addCondiments()
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    protected abstract void brew();

    protected abstract void addCondiments();

    private void boilWater() {
        System.out.println("Boiling water");
    }

    private void pourInCup() {
        System.out.println("Pouring into cup");
    }
}
public class Tea extends CaffeineBeverage{
    @Override
    protected void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding Lemon");
    }
}
public class Coffee extends CaffeineBeverage{
    @Override
    protected void brew() {
        System.out.println("Dripping Coffee through filter");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }
}

测试类

public class BeverageTestDrive {

    public static void main(String[] args) {
        Tea tea = new Tea();
        /*Boiling water
        Steeping the tea
        Pouring into cup
        Adding Lemon*/
        tea.prepareRecipe();
    }
}

看看抽象类可以有哪些类型的方法
这里写图片描述
接下来我们队模板方法进行挂钩(只写出了变化的部分)

public abstract class CaffeineBeverage {

    /*
     * 咖啡因饮料是一个抽象类
     */
    //不希望子类覆盖这个方法,并且将步骤2和步骤4泛化为brew()和addCondiments()
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        //如果顾客想要调料,只有这时我们才调用addCondiments()
        if (customerWantsClondiments()) {
            addCondiments();
        }
    }

    //定义了一个空的缺省实现,子类可以覆盖,但不见得一定要这么做
    boolean customerWantsClondiments() {
        return true;
    }
}
public class Coffee extends CaffeineBeverage{

    @Override
    boolean customerWantsClondiments() {
        String answer = getUserInput();
        if (answer.toLowerCase().startsWith("y")) {
            return true;
        } else {
            return false;
        }
    }

    private String getUserInput() {
        String answer = null;
        System.out.println("Would you like milk and sugar with you coffee (y/n) ?");
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        try {
            answer = in.readLine();
        } catch (IOException e) {
            System.err.println("IO error trying to read your answer");
        }
        if (answer == null) {
            return "no";
        }
        return answer;
    }
}

测试类

public class BeverageTestDrive {

    public static void main(String[] args) {
        Coffee coffee = new Coffee();
        /*Boiling water
        Dripping Coffee through filter
        Pouring into cup
        Would you like milk and sugar with you coffee (y/n) ? y
        Adding Sugarand  Milk*/
        coffee.prepareRecipe();
    }
}

用模板方法排序

迭代器模式

迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示

对象村餐厅和对象村煎饼屋进行合并,他们都同意菜单的表示方法,即MenuItem类,但煎饼屋是用ArrayList进行存储,餐厅是用数组存储,如果每次是获取容器在进行遍历,非常不方便,菜单的定义如下。

public class MenuItem {
    String name;
    String description;
    boolean vegetarian;
    double price;

    public MenuItem(String name, 
                    String description, 
                    boolean vegetarian, 
                    double price) 
    {
        this.name = name;
        this.description = description;
        this.vegetarian = vegetarian;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public double getPrice() {
        return price;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }
    public String toString() {
        return (name + ", $" + price + "\n   " + description);
    }
}

可以让菜单都继承Menu这个接口,接口的作用是使每个菜单都能通过统一的方法获得各自的Iterator

public interface Menu {
    public Iterator createIterator();
}

Iterator这个接口规定了遍历的方法

public interface Iterator {
    boolean hasNext();
    Object next();
}

餐厅存储实现类

public class DinerMenu implements Menu {

    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    MenuItem[] menuItems;

    public DinerMenu() {
        menuItems = new MenuItem[MAX_ITEMS];

        addItem("Vegetarian BLT",
            "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99);
        addItem("BLT",
            "Bacon with lettuce & tomato on whole wheat", false, 2.99);
        addItem("Soup of the day",
            "Soup of the day, with a side of potato salad", false, 3.29);
        addItem("Hotdog",
            "A hot dog, with saurkraut, relish, onions, topped with cheese",
            false, 3.05);
        addItem("Steamed Veggies and Brown Rice",
            "Steamed vegetables over brown rice", true, 3.99);
        addItem("Pasta",
            "Spaghetti with Marinara Sauce, and a slice of sourdough bread",
            true, 3.89);
    }

    public void addItem(String name, String description, 
                         boolean vegetarian, double price) 
    {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        if (numberOfItems >= MAX_ITEMS) {
            System.err.println("Sorry, menu is full!  Can't add item to menu");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems = numberOfItems + 1;
        }
    }

    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }

    // other menu methods here
}

餐厅存储遍历类

public class DinerMenuIterator implements Iterator {
    MenuItem[] items;
    int position = 0;

    public DinerMenuIterator(MenuItem[] items) {
        this.items = items;
    }

    public Object next() {
        MenuItem menuItem = items[position];
        position = position + 1;
        return menuItem;
    }

    public boolean hasNext() {
        if (position >= items.length || items[position] == null) {
            return false;
        } else {
            return true;
        }
    }
}

煎饼存储实现类

public class PancakeHouseMenu implements Menu {
    ArrayList menuItems;

    public PancakeHouseMenu() {
        menuItems = new ArrayList();

        addItem("K&B's Pancake Breakfast", 
            "Pancakes with scrambled eggs, and toast", 
            true,
            2.99);

        addItem("Regular Pancake Breakfast", 
            "Pancakes with fried eggs, sausage", 
            false,
            2.99);

        addItem("Blueberry Pancakes",
            "Pancakes made with fresh blueberries",
            true,
            3.49);

        addItem("Waffles",
            "Waffles, with your choice of blueberries or strawberries",
            true,
            3.59);
    }

    public void addItem(String name, String description,
                        boolean vegetarian, double price)
    {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.add(menuItem);
    }

    public Iterator createIterator() {
        return new PancakeHouseMenuIterator(menuItems);
    }

    public String toString() {
        return "Objectville Pancake House Menu";
    }

    // other menu methods here
}

当然,上述的createIterator方法可以用ArrayList的iterator()方法
煎饼遍历类

public class PancakeHouseMenuIterator implements Iterator {
    ArrayList items;
    int position = 0;

    public PancakeHouseMenuIterator(ArrayList items) {
        this.items = items;
    }

    public Object next() {
        Object object = items.get(position);
        position = position + 1;
        return object;
    }

    public boolean hasNext() {
        if (position >= items.size()) {
            return false;
        } else {
            return true;
        }
    }
}

服务员类

public class Waitress {

    Menu pancakeHouseMenu;
    Menu dinerMenu;

    public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }

    public void printMenu() {
        Iterator pancakeIterator = pancakeHouseMenu.createIterator();
        Iterator dinerIterator = dinerMenu.createIterator();

        System.out.println("MENU\n----\nBREAKFAST");
        printMenu(pancakeIterator);
        System.out.println("\nLUNCH");
        printMenu(dinerIterator);
    }

    private void printMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            System.out.print(menuItem.getName() + ", ");
            System.out.print(menuItem.getPrice() + " -- ");
            System.out.println(menuItem.getDescription());
        }
    }

    public void printVegetarianMenu() {
        printVegetarianMenu(pancakeHouseMenu.createIterator());
        printVegetarianMenu(dinerMenu.createIterator());
    }

    public boolean isItemVegetarian(String name) {
        Iterator breakfastIterator = pancakeHouseMenu.createIterator();
        if (isVegetarian(name, breakfastIterator)) {
            return true;
        }
        Iterator dinnerIterator = dinerMenu.createIterator();
        if (isVegetarian(name, dinnerIterator)) {
            return true;
        }
        return false;
    }


    private void printVegetarianMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            if (menuItem.isVegetarian()) {
                System.out.print(menuItem.getName());
                System.out.println("\t\t" + menuItem.getPrice());
                System.out.println("\t" + menuItem.getDescription());
            }
        }
    }

    private boolean isVegetarian(String name, Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            if (menuItem.getName().equals(name)) {
                if (menuItem.isVegetarian()) {
                    return true;
                }
            }
        }
        return false;
    }
}

测试类

public class MenuTestDrive {

    public static void main(String args[]) {
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        DinerMenu dinerMenu = new DinerMenu();
        Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu);
        /*
        MENU
        ----
        BREAKFAST
        K&B's Pancake Breakfast, 2.99 -- Pancakes with scrambled eggs, and toast
        Regular Pancake Breakfast, 2.99 -- Pancakes with fried eggs, sausage
        Blueberry Pancakes, 3.49 -- Pancakes made with fresh blueberries
        Waffles, 3.59 -- Waffles, with your choice of blueberries or strawberries

        LUNCH
        Vegetarian BLT, 2.99 -- (Fakin') Bacon with lettuce & tomato on whole wheat
        BLT, 2.99 -- Bacon with lettuce & tomato on whole wheat
        Soup of the day, 3.29 -- Soup of the day, with a side of potato salad
        Hotdog, 3.05 -- A hot dog, with saurkraut, relish, onions, topped with cheese
        Steamed Veggies and Brown Rice, 3.99 -- Steamed vegetables over brown rice
        Pasta, 3.89 -- Spaghetti with Marinara Sauce, and a slice of sourdough bread
        */
        waitress.printMenu();
    }
}

类图如下
这里写图片描述

组合模式

组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合

新的问题来了,每次加入新的菜单时,服务员的printMenu(Iterator)方法就得被调用,如上2个菜单调用了2次,3个菜单就得调用三次,这是一个不好的实现
这里写图片描述
然而我们不仅想支持多个菜单,还想支持菜单中的菜单,如下所示,将甜点菜单变成餐厅菜单集合的一个元素
这里写图片描述
组合模式的类图如下
这里写图片描述
改写餐厅菜单的类图
这里写图片描述

public abstract class MenuComponent {

    /*
     * 菜单组件抽象类
     */
    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }
    public void remove(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }
    public MenuComponent getChild(int i) {
        throw new UnsupportedOperationException();
    }

    public String getName() {
        throw new UnsupportedOperationException();
    }
    public String getDescription() {
        throw new UnsupportedOperationException();
    }
    public double getPrice() {
        throw new UnsupportedOperationException();
    }
    public boolean isVegetarian() {
        throw new UnsupportedOperationException();
    }

    public abstract Iterator createIterator();

    public void print() {
        throw new UnsupportedOperationException();
    }
}
import java.util.ArrayList;
import java.util.Iterator;

public class Menu extends MenuComponent{

    /*
     * 菜单类,即组合类
     */
    ArrayList menuComponents = new ArrayList();
    String name;
    String description;

    public Menu(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public void add(MenuComponent menuComponent) {
        menuComponents.add(menuComponent);
    }

    public void remove(MenuComponent menuComponent) {
        menuComponents.remove(menuComponent);
    }

    public MenuComponent getChild(int i) {
        return (MenuComponent)menuComponents.get(i);
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public Iterator createIterator() {
        return new CompositeIterator(menuComponents.iterator());
    }

    public void print() {
        System.out.print("\n" + getName());
        System.out.println(", " + getDescription());
        System.out.println("---------------------");

        Iterator iterator = menuComponents.iterator();
        while (iterator.hasNext()) {
            MenuComponent menuComponent = (MenuComponent)iterator.next();
            menuComponent.print();
        }
    }
}
import java.util.Iterator;

public class MenuItem extends MenuComponent{

    /*
     * 菜单项类,这是组合类图里的叶类
     */
    String name;
    String description;
    boolean vegetarian;
    double price;

    public MenuItem(String name,
                    String description,
                    boolean vegetarian,
                    double price)
    {
        this.name = name;
        this.description = description;
        this.vegetarian = vegetarian;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public double getPrice() {
        return price;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    @Override
    public Iterator createIterator() {
        return new NullIterator();
    }

    public void print() {
        System.out.println(" " + getName());
        if (isVegetarian()) {
            System.out.println("(v)");
        }
        System.out.println(", " + getPrice());
        System.out.println("   ----" + getDescription());
    }
}
import java.util.Iterator;
import java.util.Stack;

public class CompositeIterator implements Iterator{

    /*
     * 组合迭代器,遍历菜单和子菜单
     */
    Stack stack = new Stack();

    public CompositeIterator(Iterator iterator) {
        stack.push(iterator);
    }
    @Override
    public boolean hasNext() {
        if (stack.empty()) {
            return false;
        } else {
            //peek方法不弹出栈顶
            Iterator iterator = (Iterator) stack.peek();
            if (!iterator.hasNext()) {
                //子组合已经没有菜单项了,将栈顶元素弹出
                stack.pop();
                //返回下一个子组合的结果
                return hasNext();
            } else {
                return true;
            }
        }
    }

    @Override
    public Object next() {
        if (hasNext()) {
            //peek方法不弹出栈顶元素
            Iterator iterator = (Iterator) stack.peek();
            MenuComponent component = (MenuComponent) iterator.next();
            if (component instanceof Menu) {
                stack.push(component.createIterator());
            }
            return component;
        } else {
            return null;
        }
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

}
import java.util.Iterator;

public class NullIterator implements Iterator{

    @Override
    public boolean hasNext() {
        return false;
    }

    @Override
    public Object next() {
        return null;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}

我们可以让菜单项的createIterator()方法返回null,但是如果这么做,我们的客户代码就需要条件语句来判断返回值是否为null,因此我们创建一个迭代器,其作用是“没作用”

import java.util.Iterator;

public class Waitress {

    /*
     * 服务员类
     */
    MenuComponent allMenus;

    public Waitress(MenuComponent allMenus) {
        this.allMenus = allMenus;
    }

    public void printMenu() {
        allMenus.print();
    }

    public void printVegetarianMenu() {
        Iterator iterator = allMenus.createIterator();
        System.out.println("\nVEGETARIAN MENU\n----");
        while (iterator.hasNext()) {
            MenuComponent menuComponent = (MenuComponent)iterator.next();
            try {
                if (menuComponent.isVegetarian()) {
                    menuComponent.print();
                }
            } catch (UnsupportedOperationException e) {}
        }
    }
}

测试类

public class MenuTestDrive {

    public static void main(String args[]) {

        MenuComponent dinerMenu = new Menu("DINER MENU", "Lunch");
        MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner");
        MenuComponent dessertMenu = new Menu("DESSERT MENU", "Dessert of course!");

        MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");

        allMenus.add(dinerMenu);
        allMenus.add(cafeMenu);

        dinerMenu.add(new MenuItem(
                "Vegetarian BLT",
                "(Fakin') Bacon with lettuce & tomato on whole wheat",
                true,
                2.99));
        dinerMenu.add(new MenuItem(
                "BLT",
                "Bacon with lettuce & tomato on whole wheat",
                false,
                2.99));

        //将dessertMenu作为dinerMenu的子菜单
        dinerMenu.add(dessertMenu);

        dessertMenu.add(new MenuItem(
                "Apple Pie",
                "Apple pie with a flakey crust, topped with vanilla icecream",
                true,
                1.59));

        dessertMenu.add(new MenuItem(
                "Cheesecake",
                "Creamy New York cheesecake, with a chocolate graham crust",
                true,
                1.99));

        cafeMenu.add(new MenuItem(
                "Veggie Burger and Air Fries",
                "Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
                true,
                3.99));
        cafeMenu.add(new MenuItem(
                "Soup of the day",
                "A cup of the soup of the day, with a side salad",
                false,
                3.69));

        Waitress waitress = new Waitress(allMenus);
        waitress.printMenu();
        waitress.printVegetarianMenu();
    }
}

输出

ALL MENUS, All menus combined
---------------------

DINER MENU, Lunch
---------------------
 Vegetarian BLT
(v)
, 2.99
   ----(Fakin') Bacon with lettuce & tomato on whole wheat
 BLT
, 2.99
   ----Bacon with lettuce & tomato on whole wheat

DESSERT MENU, Dessert of course!
---------------------
 Apple Pie
(v)
, 1.59
   ----Apple pie with a flakey crust, topped with vanilla icecream
 Cheesecake
(v)
, 1.99
   ----Creamy New York cheesecake, with a chocolate graham crust

CAFE MENU, Dinner
---------------------
 Veggie Burger and Air Fries
(v)
, 3.99
   ----Veggie burger on a whole wheat bun, lettuce, tomato, and fries
 Soup of the day
, 3.69
   ----A cup of the soup of the day, with a side salad

VEGETARIAN MENU
----
 Vegetarian BLT
(v)
, 2.99
   ----(Fakin') Bacon with lettuce & tomato on whole wheat
 Apple Pie
(v)
, 1.59
   ----Apple pie with a flakey crust, topped with vanilla icecream
 Cheesecake
(v)
, 1.99
   ----Creamy New York cheesecake, with a chocolate graham crust
 Apple Pie
(v)
, 1.59
   ----Apple pie with a flakey crust, topped with vanilla icecream
 Cheesecake
(v)
, 1.99
   ----Creamy New York cheesecake, with a chocolate graham crust
 Veggie Burger and Air Fries
(v)
, 3.99
   ----Veggie burger on a whole wheat bun, lettuce, tomato, and fries

状态模式

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类

我们想让糖果机按照如下方式工作
这里写图片描述
系统从没有25分钱开始,刚开始实现如下:

public class GumballMachine {

    //糖果售完状态
    final static int SOLD_OUT = 0;
    final static int NO_QUARTER = 1;
    final static int HAS_QUARTER = 2;
    final static int SOLD = 3;

    int state = SOLD_OUT;
    int count = 0;

    public GumballMachine(int count) {
        this.count = count;
        if (count > 0) {
            state = NO_QUARTER;
        }
    }

    public void insertQuarter() {
        if (state == HAS_QUARTER) {
            System.out.println("You can't insert another quarter");
        } else if (state == NO_QUARTER) {
            state = HAS_QUARTER;
            System.out.println("You inserted a quarter");
        } else if (state == SOLD_OUT) {
            System.out.println("You can't insert a quarter, the machine is sold out");
        } else if (state == SOLD) {
            System.out.println("Please wait, we're already giving you a gumball");
        }
    }

    public void ejectQuarter() {
        if (state == HAS_QUARTER) {
            System.out.println("Quarter returned");
            state = NO_QUARTER;
        } else if (state == NO_QUARTER) {
            System.out.println("You haven't inserted a quarter");
        } else if (state == SOLD) {
            System.out.println("Sorry, you already turned the crank");
        } else if (state == SOLD_OUT) {
            System.out.println("You can't eject, you haven't inserted a quarter yet");
        }
    }

    public void turnCrank() {
        if (state == SOLD) {
            System.out.println("Turning twice doesn't get you another gumball!");
        } else if (state == NO_QUARTER) {
            System.out.println("You turned but there's no quarter");
        } else if (state == SOLD_OUT) {
            System.out.println("You turned, but there are no gumballs");
        } else if (state == HAS_QUARTER) {
            System.out.println("You turned...");
            state = SOLD;
            dispense();
        }
    }

    public void dispense() {
        if (state == SOLD) {
            System.out.println("A gumball comes rolling out the slot");
            count = count - 1;
            if (count == 0) {
                System.out.println("Oops, out of gumballs!");
                state = SOLD_OUT;
            } else {
                state = NO_QUARTER;
            }
        } else if (state == NO_QUARTER) {
            System.out.println("You need to pay first");
        } else if (state == SOLD_OUT) {
            System.out.println("No gumball dispensed");
        } else if (state == HAS_QUARTER) {
            System.out.println("No gumball dispensed");
        }
    }

    public void refill(int numGumBalls) {
        this.count = numGumBalls;
        state = NO_QUARTER;
    }

    public String toString() {
        StringBuffer result = new StringBuffer();
        result.append("Inventory: " + count + " gumball");
        if (count != 1) {
            result.append("s");
        }
        result.append("\nMachine is ");
        if (state == SOLD_OUT) {
            result.append("sold out");
        } else if (state == NO_QUARTER) {
            result.append("waiting for quarter");
        } else if (state == HAS_QUARTER) {
            result.append("waiting for turn of crank");
        } else if (state == SOLD) {
            result.append("delivering a gumball");
        }
        result.append("\n");
        return result.toString();
    }
}

测试类

public class GumballMachineTestDrive {

    public static void main(String[] args) {

        GumballMachine gumballMachine = new GumballMachine(5);
        //Inventory: 5 gumballs
        //Machine is waiting for quarter
        System.out.println(gumballMachine);
        //You inserted a quarter
        gumballMachine.insertQuarter();
        //You can't insert another quarter
        gumballMachine.insertQuarter();
        //You turned...
        //A gumball comes rolling out the slot
        gumballMachine.turnCrank();
        //Inventory: 4 gumballs
        //Machine is waiting for quarter
        System.out.println(gumballMachine);
    }
}

需求发生变更,当曲柄被转动时,有10%的几率掉下来的是两颗糖果,多送一个,我们可以把状态定义成单独的类,并且实现共同的接口
这里写图片描述
实现如下

public interface State {

    /*
    * 定义状态类的接口
    */
    //投币
    public void insertQuarter();
    //退币
    public void ejectQuarter();
    //转动曲柄
    public void turnCrank();
    //发放糖果
    public void dispense();
}
public class HasQuarterState implements State {
    Random randomWinner = new Random(System.currentTimeMillis());
    GumballMachine gumballMachine;

    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    public void insertQuarter() {
        System.out.println("You can't insert another quarter");
    }

    public void ejectQuarter() {
        System.out.println("Quarter returned");
        gumballMachine.setState(gumballMachine.getNoQuarterState());
    }

    public void turnCrank() {
        System.out.println("You turned...");
        //返回[0,10)之间均匀分布的int值
        int winner = randomWinner.nextInt(10);
        //只有糖果机至少有2个糖果时,才能变为幸运客户
        if ((winner == 0) && (gumballMachine.getCount() > 1)) {
            gumballMachine.setState(gumballMachine.getWinnerState());
        } else {
            gumballMachine.setState(gumballMachine.getSoldState());
        }
    }

    public void dispense() {
        System.out.println("No gumball dispensed");
    }

    public String toString() {
        return "waiting for turn of crank";
    }
}
public class WinnerState implements State {
    GumballMachine gumballMachine;

    public WinnerState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    public void insertQuarter() {
        System.out.println("Please wait, we're already giving you a Gumball");
    }

    public void ejectQuarter() {
        System.out.println("Please wait, we're already giving you a Gumball");
    }

    public void turnCrank() {
        System.out.println("Turning again doesn't get you another gumball!");
    }

    public void dispense() {
        //这个是书上的代码,不修改了,感觉可以直接出两个糖果,没必要判断为零的情况,因为只有糖果机中的糖果数大于1时
        //状态才有可能变为WinnerSate
        System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");
        gumballMachine.releaseBall();
        if (gumballMachine.getCount() == 0) {
            gumballMachine.setState(gumballMachine.getSoldOutState());
        } else {
            gumballMachine.releaseBall();
            if (gumballMachine.getCount() > 0) {
                gumballMachine.setState(gumballMachine.getNoQuarterState());
            } else {
                System.out.println("Oops, out of gumballs!");
                gumballMachine.setState(gumballMachine.getSoldOutState());
            }
        }
    }

    public String toString() {
        return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";
    }
}

机器类的代码更改为如下

public class GumballMachine {

    State soldOutState;
    State noQuarterState;
    State hasQuarterState;
    State soldState;
    State winnerState;

    State state = soldOutState;
    int count = 0;

    public GumballMachine(int numberGumballs) {
        soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);
        winnerState = new WinnerState(this);

        this.count = numberGumballs;
        if (numberGumballs > 0) {
            state = noQuarterState;
        } 
    }

    public void insertQuarter() {
        state.insertQuarter();
    }

    public void ejectQuarter() {
        state.ejectQuarter();
    }

    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }

    void setState(State state) {
        this.state = state;
    }

    void releaseBall() {
        System.out.println("A gumball comes rolling out the slot...");
        if (count != 0) {
            count = count - 1;
        }
    }

    int getCount() {
        return count;
    }

    void refill(int count) {
        this.count = count;
        state = noQuarterState;
    }

    public State getState() {
        return state;
    }

    public State getSoldOutState() {
        return soldOutState;
    }

    public State getNoQuarterState() {
        return noQuarterState;
    }

    public State getHasQuarterState() {
        return hasQuarterState;
    }

    public State getSoldState() {
        return soldState;
    }

    public State getWinnerState() {
        return winnerState;
    }

    public String toString() {
        StringBuffer result = new StringBuffer();
        result.append("\nInventory: " + count + " gumball");
        if (count != 1) {
            result.append("s");
        }
        result.append("\n");
        result.append("Machine is " + state + "\n");
        return result.toString();
    }
}

测试类和上面类似,状态模式的类图
这里写图片描述

责任链模式

AbstractLogger.java

public abstract class AbstractLogger {

    public static int INFO = 1;
    public static int DEBUG = 2;
    public static int ERROR = 3;

    protected int level;

    protected AbstractLogger nextLogger;

    public void setNextLogger(AbstractLogger nextLogger) {
        this.nextLogger = nextLogger;
    }

    public void logMessage(int level, String message) {
        if (this.level <= level) {
            write(message);
        }
        if (nextLogger != null) {
            nextLogger.logMessage(level, message);
        }
    }

    abstract protected void write (String message);

}

InfoLogger.java

public class InfoLogger extends AbstractLogger {

    public InfoLogger(int level) {
        this.level = level;
    }
    protected void write(String message) {
        System.out.println("Ingo:Logger" + message);
    }
}

DebugLogger.java

public class DebugLogger extends AbstractLogger {

    public DebugLogger(int level) {
        this.level = level;
    }
    protected void write(String message) {
        System.out.println("Debug:Logger" + message);
    }
}

ErrorLogger.java

public class ErrorLogger extends AbstractLogger {

    public ErrorLogger(int level) {
        this.level = level;
    }
    protected void write(String message) {
        System.out.println("Error:Logger" + message);
    }
}

ChainPatternDemo.java

public class ChainPatternDemo {

    private static AbstractLogger getChainOfLoggers() {
        InfoLogger infoLogger = new InfoLogger(AbstractLogger.INFO);
        DebugLogger debugLogger = new DebugLogger(AbstractLogger.DEBUG);
        ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);

        errorLogger.setNextLogger(debugLogger);
        debugLogger.setNextLogger(infoLogger);

        return errorLogger;
    }

    public static void main(String[] args) {

        AbstractLogger loggerChain = getChainOfLoggers();
        //Ingo:Loggerinfo level
        loggerChain.logMessage(AbstractLogger.INFO, "info level");
        System.out.println();
        //Debug:Loggerdebug level
        //Ingo:Loggerdebug level
        loggerChain.logMessage(AbstractLogger.DEBUG, "debug level");
        System.out.println();
        //Error:Loggererror level
        //Debug:Loggererror level
        //Ingo:Loggererror level
        loggerChain.logMessage(AbstractLogger.ERROR, "error level");
    }
}

参考博客:
责任链模式
[1]http://www.cnblogs.com/V1haoge/p/6530089.html
[2]http://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java识堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值