Java设计模式之装饰模式
要学习并理解Java I/O,那么首先要学习Java设计模式中的装饰设计模式。
顾名思义,装饰设计模式的核心概念为通过"装饰"来扩展原有类的功能,而不是通过继承。
其要解决的主要问题是:
在某些特定情况下,需要对原有类的功能进行扩展,扩展方式有很多类型,并且相互之间存在很多组合。
如果采用继承的方式来实现这个需求,那么将会产生大量的子类,整个类设计的体系结构将显得十分臃肿。
装饰的思想是:在原有类的基础上,通过将原有类对象通过构造函数传入装饰类中,装饰类在原有类功能的基础上进行增强,提供增强功能。
需要注意的是:装饰类和被装饰类应该实现同样的接口(或至少继承自同一父类),装饰类中构造函数参数的类型应写成接口形式,以便利用多态的思想,
由接口调用方法时,执行的是具体实现子类的覆盖方法。从而形成一种连锁的、链式的装饰。
下面用一个具体的例子来说明:
/**
* 具体被装饰者要实现的接口
* 装饰类要与被装饰类实现同样的接口
* @author Administrator
*
*/
public interface Hamberger {
public String getName();
public float getPrice();
}
/**
* 具体的被装饰类
* 即被装饰主体是 ¥15.00 的 鸡腿堡
* @author Administrator
*
*/
public class ChickenHamberger implements Hamberger {
@Override
public String getName() {
return "鸡腿堡";
}
@Override
public float getPrice() {
return 15.0f;
}
}
/**
* 定义一个装饰类
* @author Administrator
*
*/
public abstract class Decorator implements Hamberger {
private Hamberger hamberger;
public Decorator(Hamberger hamberger){
this.hamberger = hamberger;
}
@Override
public String getName() {
return hamberger.getName();
}
@Override
public float getPrice() {
return hamberger.getPrice();
}
}
/**
* 定义一种具体的装饰
* 鸡腿堡+生菜+¥5.0
* @author Administrator
*
*/
public class DecoratorA extends Decorator {
public DecoratorA(Hamberger hamberger) {
super(hamberger);
}
public String addLettuce(){
return "加生菜";
}
public float addPrice(){
return 5f;
}
@Override
public String getName() {
return super.getName()+addLettuce();
}
@Override
public float getPrice() {
return super.getPrice()+addPrice();
}
}
/**
* 定义一种具体的装饰
* 鸡腿堡+生菜+¥2.0
* @author Administrator
*
*/
public class DecoratorB extends Decorator {
public DecoratorB(Hamberger hamberger) {
super(hamberger);
}
public String addPepper(){
return "加辣椒";
}
public float addPrice(){
return 2f;
}
@Override
public String getName() {
return super.getName()+addPepper();
}
@Override
public float getPrice() {
return super.getPrice()+addPrice();
}
}
/**
* 进行测试
* @author Administrator
*
*/
public class DecoratorTest {
@Test
public void test(){
Hamberger hamberger = new ChickenHamberger();
Decorator decorator = new DecoratorB(new DecoratorA(hamberger));
String name = decorator.getName();
float price = decorator.getPrice();
System.out.println(name);
System.out.println(price);
}
}
结果是:
鸡腿堡加生菜加辣椒
22.0
可以看到,通过
Decorator decorator = new DecoratorB(new DecoratorA(hamberger));
这种方式,成功地对原来的”汉堡“,增加了”生菜“和”辣椒“,如果只需要加”生菜“或者”辣椒“中的一种、或者调整其顺序的话,也只需要在这行代码中更改要用的装饰类型,并根据需要调整顺序即可。
有必要对结果的产生过程做一个分析,以
String name = decorator.getName();
为例。
通过装饰抽象类Decorator来调用getName()方法,decorator引用类型变量指向的是DecoratorB装饰类对象,将调用DecoratorB中的getName()方法。
public String getName() {
return super.getName()+addPepper();
}
要调用此方法,首先要调用其父类
Decorator的getName()方法,
@Override
public String getName() {
return hamberger.getName();
}
这里的hamberger对象指向的是
DecoratorB类型对象初始化时向其构造函数传入的DecoratorA的实例,即将执行DecoratorA的实例对象的getName()方法,
@Override
public String getName() {
return super.getName()+addLettuce();
}
同样的,也将执行
DecoratorA对象父类的getName()方法,
DecoratorA类型对象初始化直接依赖的是ChickenHamberger对象,
通过构造函数向其父类传入的是ChickenHamberger对象,即此时父类的hamberger引用指向的是ChickenHamberger对象。
调用其getName()方法将打印”鸡肉堡“,然后执行addLettuce()方法,”加生菜“,最后执行addPepper()方法,加”辣椒“。
价格的过程也以此类推。
总结几点:
1、可以看到,采用装饰设计模式,在避免大量子类继承的同时,增加了灵活性与动态性。即,采用子类继承,必须预先想好要扩展的功能并写死!但是采用装饰设计模式
则大可不必,根据需要,选取合适的装饰进行组合即可。
2、同时,装饰设计模式可扩展性也很好,只需要继承抽象装饰基类,定义新的装饰类型即可。