1、装饰模式(Decorator)
当我们扩展一个类时,通常使用继承子类的方式,但当扩展的功能比较多的时候,子类会变得比较臃肿,在这种情况下,除了使用delegation以外,还可以使用装饰模式。装饰模式形象地理解就是往类上套上包装进行装饰,也就是说在不改变类结构的前提下,向现有的对象提供新的功能,因此这是一种结构性模式。
- 装饰模式的应用场景:当需要给一个现有类添加附加职责,但该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类;当对象的功能要求可以动态地添加,也可以再动态地撤销时;
- Java中装饰模式的应用;InputStream 的子类 FilterInputStream、Reader 的子类 BufferedReader 以及FilterReader等都是抽象装饰模式。
- 装饰模式的框架:
抽象模式实例
以鸡蛋饼为例,在初始版本上,可以增加香肠、生菜、里脊等多种食材,而这一些食材就可以视作装饰,鸡蛋饼就是被装饰的对象。
首先创建被装饰对象接口和其初始版本。
public interface Omelette{//鸡蛋饼类
public void addIngredients();
}
public class originOmelette implements Omelette{//未装饰类
@Override
public void addIngredients(){
System.out.println("The general Omelette!");
}
}
接下来创建装饰器基类和具体的装饰器;
public abstract class Decorator implements Omelette{//装饰器基类
protected Omelette input;
public Decorator(Omelette input){
this.input=input;
}
public abstract void addIngredients();//在具体装饰器实现
}
public class sausageDecorator extends Decorator{//装饰香肠
public sausageDecortor(Omelette input){
super(input);
}
@Override
public void addIngredients(){
input.addIngredients();
System.out.println("The Omelette is decorated with sausage");
}
}
public class lettuceDecorator extends Decorator{//装饰生菜,和香肠装饰类相似
...
}
...
在Client端调用
public class Client{
public static void main(String[] args){
Omelette one=new originOmelette();//初始未装饰类
Omelette two=new sausageDecorator(a);
Omelette three=new lettuceDecorator(b);
three.addIngredients();
}
}
- 装饰模式的优点:采用装饰模式扩展对象的功能比采用继承方式扩展性和灵活性更好;可以设计出多个不同的具体装饰类,创造出多个不同行为的组合,而对于采用继承方式来说,多种组合会出现组合爆炸的情况。
- 装饰模式的缺点:装饰层数比较多时,会增加较多子类。
2、外观模式(Facade)
外观模式为客户端提供一个窗口来访问子系统,这个窗口实际上就是一个更高层的接口,也可以视之为系统的入口。当客户端不需要知道子系统内部各部分之间的复杂关系时,可以使用外观模式。
- 外观模式的应用场景:当一个复杂系统的子系统很多时,使用外观模式为系统设计一个简单的接口供客户端访问;当客户端与多个子系统之间存在很大联系时,引入外观模式可以将它们分离。
- 外观模式的结构:
- 外观模式的代码框架;
首先给出子系统类
public class featuresOne{//三个子系统类和对应的实现方法
public void method1(){
...
}
...
}
public class featuresTwo{
public void method2(){
...
}
...
}
public class featuresThree{
public void method3(){
...
}
...
}
给出外观类
public class Facade{
private featuresOne feature1=new FeaturesOne();
private featuresTwo feature2=new FeaturesTwo();
private featuresThree feature3=new FeaturesThree();
public void Method1(){
feature1.method1();
}
public void Method2(){
feature1.method2();
}
public void Method3(){
feature1.method3();
}
}
Client端调用
public class Client{
public static void main(String[] args){
Facade facade=new Facade();
facade.Method1();
facade.Method2();
facade.Method3();
}
- 外观模式的优点:降低子系统和客户端之间的耦合度,使子系统变化不会影响调用它的客户端;减少客户端处理对象的数目;
- 外观模式的缺点:增加新的子系统需要修改外观类和客户端,修改子系统重写和继承都不太方便;
- 外观模式的改进:对于外观模式的缺点,可以引入抽象外观类,对于不同的具体外观类来说可以对子系统进行组合。