设计模式学习笔记

来源:互联网 发布:淘宝怎么设置花呗支付 编辑:程序博客网 时间:2024/06/06 09:00

策略模式

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

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

这里写图片描述
这样做会让橡皮鸭也具备飞的行为,虽然在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 wheatDESSERT 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 crustCAFE 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 saladVEGETARIAN 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();    }}

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

0 0