设计模式学习笔记

网友投稿 924 2022-09-01

设计模式学习笔记

设计模式学习笔记

策略模式

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

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

这样做会让橡皮鸭也具备飞的行为,虽然在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

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

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

观察者模式

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

为了展示气象数据而封装了一个数据对象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

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

实现布告板

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

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

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() + " $"

装饰Java io类

test.txt

This Is Just For

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

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

工厂模式

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

有订购披萨的工具如下

当披萨菜单发生改变时,代码必须进行修改。我们可以把创建对象移到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

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

public class CheesePizza extends Pizza{ PizzaIngredientFactory ingredientFactory; public CheesePizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; } @Override void prepare() { System.out.println("Preparing "

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

看类图了解关系

从PizzaStore的观点来看

单例模式

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

经典的单例模式实现

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

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

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

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

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

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

命令模式

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

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

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

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

命令模式的作用:

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

适配器模式

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

包装了鸭子适配器的火鸡

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

类图

外观模式

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

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

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*/

看看抽象类可以有哪些类型的方法

接下来我们队模板方法进行挂钩(只写出了变化的部分)

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

测试类

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*/

用模板方法排序

迭代器模式

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

对象村餐厅和对象村煎饼屋进行合并,他们都同意菜单的表示方法,即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 "

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

public interface Menu { public Iterator createIterator();}

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

public interface

餐厅存储实现类

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

类图如下

组合模式

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

新的问题来了,每次加入新的菜单时,服务员的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

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

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(" ----"

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

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

我们可以让菜单项的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

测试类

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

输出

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

测试类

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

测试类和上面类似,状态模式的类图

责任链模式

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

InfoLogger.java

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

DebugLogger.java

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

ErrorLogger.java

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

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"); }}

参考博客: 责任链模式 ​​ [2]​​​http://runoob.com/design-pattern/chain-of-responsibility-pattern.html​​

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:mongodb入门教程
下一篇:面试官出的MySQL索引问题,这篇文章全给你解决!(mysql调优面试题)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~