本文共 3385 字,大约阅读时间需要 11 分钟。
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
java IO 流是装饰模式一个典型的应用场景。
举个生活中的例子,饮品店的饮料价格由原料(咖啡、茶……)价格和配料(糖、奶泡……)价格组成,我们是计算价格的呢?如果为每一种组合创建一个类,显然不现实。但是如果我们把每一种饮品看作是配料对原料的修饰,那就简单多了,参考上述类图,我么可以新建Beverage类,这是饮料的基类,提供一个抽象方法用于计算饮料价格:
Beverage.java
public abstract class Beverage { String description = "Unknown Beverage"; public String getDescription(){ return description; } public abstract double cost();}
在此基础上我们创建两个具体的原料类型Espresso和HouseBlend:
Espresso.java
public class Espresso extends Beverage { public Espresso(){ this.description = "Espresso"; } public double cost() { return 1.99; }}
HouseBlend.java
public class HouseBlend extends Beverage{ public HouseBlend(){ this.description = "House Blend Coffee"; } public double cost() { return 0.89; }}
再来创建修饰类的基类Decorator和具体类Mocha:
Decorator.java
public abstract class Decorator extends Beverage { public abstract String getDescription();}
Mocha.java
public class Mocha extends Decorator{ private Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } public String getDescription() { return beverage.getDescription() + ", Mocha"; } public double cost() { return 0.2 + this.beverage.cost(); }}
如果我们想要一杯HouseBlend配加一分Mocha,一杯Espresso配加两份Mocha,就可以如下实现:
public class DecoratorTest { public static void main(String[] args) { //创建一个HouseBlend对象 Beverage beverage = new HouseBlend(); //用Mocha来修饰上述HouseBlend对象 Beverage beverage1 = new Mocha(beverage); System.out.println(beverage1.getDescription() + " $" + beverage1.cost()); System.out.println("====================================="); //创建一个Espresso对象 beverage = new Espresso(); //用2份Mocha来修饰上述HouseBlend对象 Beverage beverage2 = new Mocha(beverage); beverage2 = new Mocha(beverage2); System.out.println(beverage2.getDescription() + " $" + beverage2.cost()); }}
运行结果:
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。——Gang of Four
我们生活中电子产品的工作电压一般都在36V以下,但是家里都是220V的交流电,这个时候便有了电源适配器这种东西。范围再广一点,大陆和香港地区的三相插座不一样,一般商家向大陆顾客出售产品的时候会额外提供一个插座的转换口。
生活中适配器的例子比比皆是,放到程序设计中来,当一个类接口不是客户想要的那种,我们便可以通过适配器方式转换该接口来满足需求。
Adaptee.java
public interface Adaptee { //需要被适配的类,目标接口 void adaptedOperation();}
ConcreteAdaptee.java
public class ConcreteAdaptee implements Adaptee { public void adaptedOperation() { System.out.println("this is a concrete adaptee!"); }}
Adaptor.java
public interface Adaptor { //适配类,即客户希望访问的接口 void doSomething();}
ConcreteAdaptor.java
public class ConcreteAdaptor implements Adaptor { private Adaptee adaptee; public ConcreteAdaptor(Adaptee adaptee) { this.adaptee = adaptee; } public void doSomething() { this.adaptee.adaptedOperation(); }}
当我们希望通过访问适配方法实现对目标方法的访问,便可以如下实现:
public class AdaptorTest { public static void main(String[] args) { //目标接口 Adaptee adaptee = new ConcreteAdaptee(); //适配目标接口 Adaptor adaptor = new ConcreteAdaptor(adaptee); //通过访问适配方法实现访问目标方法 adaptor.doSomething(); }}
运行结果:
外观模式通过封装许多对象,以简化它们的接口,此模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。
最少知识原则是门面模式遵循的一个设计原则。
最少知识原则:只和你的密友谈话。
这个原则希望我们在设计中,不要让太多的类耦合在一起,免得修改系统的一部分,会影响到其他部分。
详见博主之前的文章