近期项目里要用到很多参数类,每个参数类都有着不同的功能,为了维护方便,抽象出一个基本的基类,然后通过继承来维护,但是每个类相差不多,想到了装饰者模式进行。由于项目改动会牵扯巨大,自己写了一个测试。给一顿餐加食物,例子可能不是很形象。
面对这种逐渐多的子类需求,可能会很乱,装饰者是一种代替生成子类的方式动态的给对象增加功能的设计模式。
抽象基类:
public abstract class Meal {
public abstract void addMeal();
}
抽象基类里面有一个抽象的方法,给餐加东西
早餐类:
public class Breakfast extends Meal {
@Override
public void addMeal() {
System.out.println("this is Breakfast");
}
}
重写了加餐的方法,执行它特定的功能。
装饰类Decorate:
public abstract class Decorator extends Meal {
private Meal meal;
public Decorator(Meal meal) {
this.meal = meal;
}
@Override
public void addMeal() {
meal.addMeal();
}
}
装饰类持有一个餐的实例变量,通过构造方法初始化,并重写addMeal()方法。
具体的加东西类:
public class Beef extends Decorator {
public Beef(Meal meal) {
super(meal);
}
@Override
public void addMeal() {
System.out.println("add beef");
super.addMeal();
}
}
public class Fruit extends Decorator {
public Fruit(Meal meal) {
super(meal);
}
public void out() {
System.out.println("add fruit");
}
@Override
public void addMeal() {
this.out();
super.addMeal();
}
}
这里具体的加功能的类,继承了装饰类Decorator,通过带参数的构造方法调用super来指向父类的构造方法,初始化当前类的Meal实例的类型。这里的调用父类,是为了拿到一个父类的Meal引用,用来在当前类对象调用super方法时拿到相应的类型,这个引用通过调用Decorator来赋予类型,然后保存在这个类中,这里与java对象初始化内存机制有关。
这里两个功能类的操作分别是在addMeal的重写方法里进行,或者在重写方法里调用当前类的特有方法进行。
main函数执行:
public class Main {
public static void main(String[] args) {
Meal meal;
meal = new Breakfast();
meal = new Beef(meal);
meal = new Fruit(meal);
meal.addMeal();
}
}
通过debug来遍历整个程序的调用顺序,首先声明一个Meal类型的变量,将meal实例化为Breakfast类型,然后调用Beef的构造方法,Beef的构造方法会调用Decorator的构造方法,Decorator的构造方法将传进来的Breakfast类型的meal变量赋值给当前的meal变量,在Beef类初始化的过程中,Beef的父类类型就为Breakfast类型存入了他的初始化进程中。然后meal变量调用Fruit构造方法,与上面一样,Fruit的父类类型就为Beef类型,存入类的初始化信息里。
变量meal开始执行addMeal方法,目前的meal变量是Fruit类型,因为最后一次赋值是new Fruit(meal);
1.执行Fruit类的addMeal方法。
2.执行Fruit类的out方法。//输出
3.调用super方法,父类类型为Beef类型,执行Beef类的addMeal方法。
4.执行方法里的sysout函数//输出
5.调用super方法,父类类型为Breakfast类型,执行Breakfast的addMeal方法。//输出
程序执行完成后输出为:
add fruit
add beef
this is Breakfast
就是用到哪个功能,就调用相应类的构造方法,先后的顺序可以通过调用构造方法的顺序和重写方法的结构控制。
这里的Decorator和Breakfast同时继承了Meal抽象类,是为了便于扩展不同的装饰对象,比如lunch,dinner等。如果不考虑可以Decorator直接继承Breakfast即可。