定义:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
继承是静态地为类增加功能,而装饰模式则是动态地增加功能。
一、罪恶的成绩单
成绩分考低了。给老爸说的时候,多点解识,猥琐点
1. 抽象成绩单
public abstract class SchoolReport {
//成绩单主要展示的就是你的成绩情况
public abstract void report();
//成绩单要家长签字,这个是最要命的
public abstract void sign(String name);
}
2. 四年级成绩单
public class FouthGradeSchoolReport extends SchoolReport{
//我的成绩单
public void report() {
//成绩单的格式是这个样式的
System.out.println("尊敬的XXX家长:");
System.out.println(" ....");
System.out.println(" 语文62 数学65 体育98 自然63 ");
System.out.println(" ....");
System.out.println(" 家系签名");
}
//家长签名
public void sign(String name) {
System.out.println("家长签名为:"+name);
}
}
3. 增加专门的修饰的抽象类
public abstract class Decorator extends SchoolReport{
//首先我要知道是哪个成绩单
private SchoolReport sr;
//构造函数,传递成绩单过来
public Decorator(SchoolReport sr) {
this.sr = sr;
}
//成绩单还是要被看到的
public void report() {
this.sr.report();
}
//看完还是要签名的
public void sign(String name) {
this.sr.sign(name);
}
}
4. 最高成绩修饰
public class HighScoreDecorator extends Decorator{
//构造函数
public HighScoreDecorator(SchoolReport sr) {
super(sr);
}
//我要汇报最高成绩
private void reportHighScore() {
System.out.println("这次考试语言最高是75,数学是78,自然是80");
}
//我要在老爸看成绩单前告诉他最高成绩,否则等他一看,就抡起扫帚了。
public void report() {
this.reportHighScore();
super.report();
}
}
5. 排名情况修饰
public class SortDecorator extends Decorator{
//构造函数
public SortDecorator(SchoolReport sr) {
super(sr);
}
//告诉老爸学校的排名情况
private void reportSort(){
System.out.println("我是排名第38名...");
}
//老爸看完成绩单后再告诉他,加强作用
public void report() {
super.report();
this.reportSort();
}
}
6. 老爸查看修饰后的成绩单
public class Father {
public static void main(String[] args) {
//把成绩单拿过来
SchoolReport sr;
//原装的成绩单
sr = new FouthGradeSchoolReport();
//加了最高分说明的成绩单
sr = new HighScoreDecorator(sr);
//又加了成绩排名的说明
sr = new SortDecorator(sr);
//看成绩单
sr.report();
//然后老爸一看,很开心,签名了
sr.sign("老三");
}
}
二、装饰模式的定义
![](https://i-blog.csdnimg.cn/blog_migrate/7e0eeb6c584a595b640d1aa4a27208dd.png)
1. 抽象构件
public abstract class Component {
//抽象的方法
public abstract void operate();
}
2. 具体构件
public class ConcreteComponent extends Component{
//具体实现
@Override
public void operate() {
System.out.println("do Something");
}
}
3. 抽象装饰者
public class Decorator extends Component{
private Component component = null;
//通过构造函数传递被修饰者
public Decorator(Component component) {
this.component = component;
}
//委托给被修饰者执行
@Override
public void operate() {
this.component.operate();
}
}
4. 具体装饰者
public class ConcreteDecorator1 extends Decorator{
//定义被修饰者
public ConcreteDecorator1(Component component) {
super(component);
}
//定义自己的修饰方法
private void method1(){
System.out.println("method1 修饰");
}
//重写父类的Operation方法
@Override
public void operate() {
this.method1();
super.operate();
}
}
&
public class ConcreteDecorator2 extends Decorator{
//定义被修饰者
public ConcreteDecorator2(Component component) {
super(component);
}
//定义自己的修饰方法
private void method2(){
System.out.println("method2 修饰");
}
//重写父类的Operation方法
public void operate(){
super.operate();
this.method2();
}
}
5. 场景类
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
//第一次修饰
component = new ConcreteDecorator1(component);
//第二次修饰
component = new ConcreteDecorator2(component);
//修饰后运行
component.operate();
}
}
三、装饰模式应用
1. 装饰模式的优点
1) 装饰类的被装饰类可以独立发展,不会相互耦合,Component类无须知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件。
2)装饰模式是继承关系的一个替代方案。装饰类Decorator不管装饰多少层,返回的对象还是Component。
3)可以动态地扩展一个实现 类的功能。
2. 装饰模式的缺点
多层的装饰是比较复杂,难以维护,就像剥洋葱,肃到最后才发现最里层的装饰出现了问题,会导致工作量很大。因此,尽量减少装饰类的数量,以便降低系统的复杂度。
3. 使用场景
1)需要扩展一个类的功能,或给一个类增加附加功能
2)需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
3)需要为一批兄弟类进行改装或加装功能,当然是首先装饰模式。
四、最佳实践
三个继承关系Father、Son、GrandSon三个类,我要在Son类上增强一些功能怎么办?普通办法会导致GrandSon代码修改很多,其实我们可以通过建立SonDecorator类来修饰Son,相当于创建一个新的类,这个对原有程序没有变更。