设计模式 | 装饰模式(decorator)
定义:
装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
结构:(书中图,侵删)
一个被装饰接口类:从具体类中抽象出来,拥有用于修饰的一个公共方法
若干被装饰具体类;继承于被装饰接口类
一个抽象装饰类:继承于被装饰接口类
若干具体装饰类:具体的装饰方法
装饰模式是为了扩展原有方法(即已经存在的方法)的功能 ,所以是为了给方法添加功能,而不是给类新增方法。(我一开始就这么误解了,导致整个看下来感觉怪怪的,后面才后知后觉的反应过来)。
直接在原类中增加违反了开放-封闭原则;使用继承都写在子类中没有那么灵活,且不好复用。
实例:
模拟宠物去做造型
美容院提供:洗澡、染色、修剪、穿衣服等服务。
被装饰接口类:宠物类
package designpattern.decorator; public abstract class Pet { String name; Pet() {// 因为子类要使用其他参数的构造函数,需要调用父类的默认(无参)构造方法 } Pet(String name) { this.name = name; } Pet(String name, int test) { this.name = name; } public abstract void beautify(); }
若干被装饰具体类:猫、狗
package designpattern.decorator; public class Cat extends Pet { public Cat(String name) { this.name = name; } @Override public void beautify() { System.out.println(name + ":猫正在打扮~"); } }
package designpattern.decorator; public class Dog extends Pet { public Dog(String name) { this.name = name; } @Override public void beautify() { System.out.println(name + ":狗正在打扮~"); } }
抽象装饰类:美容类
package designpattern.decorator; public class Beautify extends Pet { Pet pet; Beautify(Pet pet) { this.pet = pet; } @Override public void beautify() { System.out.println("装饰父类beautify()"); pet.beautify(); } }
若干具体装饰类:洗澡、染色、修剪、穿衣服
package designpattern.decorator; public class Shower extends Beautify{ Shower(Pet pet) { super(pet); } @Override public void beautify() { super.beautify(); System.out.println("洗澡"); } }
package designpattern.decorator; public class Dye extends Beautify { Dye(Pet pet) { super(pet); } @Override public void beautify() { super.beautify(); System.out.println("染色"); } }
package designpattern.decorator; public class Trim extends Beautify { Trim(Pet pet) { super(pet); } @Override public void beautify() { super.beautify(); System.out.println("修剪"); } }
package designpattern.decorator; public class Dress extends Beautify { Dress(Pet pet) { super(pet); } @Override public void beautify() { super.beautify(); System.out.println("穿衣服"); } }
客户端调用:
package designpattern.decorator; public class Client { public static void main(String[] args) { Cat cat = new Cat("小喵"); // 直接调用 cat.beautify(); System.out.println("----------------"); // 装饰后调用 Shower showerCat = new Shower(cat); Dye dyeCat = new Dye(showerCat); Trim trimCat = new Trim(dyeCat); trimCat.beautify();
System.out.println("==================");
Dog dog = new Dog("小汪"); // 直接调用 dog.beautify(); System.out.println("----------------"); // 装饰后调用 Shower showerDog = new Shower(dog); Dress dressDog = new Dress(showerDog); dressDog.beautify(); } }
结果:
小喵:猫正在打扮~ ---------------- 装饰父类beautify() 装饰父类beautify() 装饰父类beautify() 小喵:猫正在打扮~ 洗澡 染色 修剪 ================== 小汪:狗正在打扮~ ---------------- 装饰父类beautify() 装饰父类beautify() 小汪:狗正在打扮~ 洗澡 穿衣服
从输出能看出,有几层装饰,就会调用几次装饰父类的beautify()方法。
以上例的狗小汪为例:
通过最底层的穿衣服Dress的方法:
进入方法中
通过super.beautify()方法,调用父类的方法:
再通过多态调用具体的父类,此处为洗澡Shower的方法,重复上述步骤直至最顶层狗Dog类的beautify()方法:
再回来执行方法中的其余语句,有一点类似于递归的感觉。
总结:
装饰模式虽然能灵活复用,且能够规定各个装饰办法的执行顺序。
但是一旦装饰类变多后,客户端的调用会变得相当繁琐。