不学无数 — 装饰模式

栏目: 后端 · 发布时间: 7年前

内容简介:我们可以用一个简单的例子引出来装饰模式,在小的时候,相信大家都有过这样的经历:小学每年会有好几次的考试,如果有一次成绩非常差,而且考完以后学校会有个很损的招,就是打印出来成绩单,然后让家长签字。那么拿着这个成绩单,肯定是不会直接告诉家长成绩什么的,肯定是会加一些,例如,语文考了65,就会说我们班最高的才75。如果成绩单没有排名的话,那么也会添油加醋的说排名靠前,这样父母的就会被你说的所迷惑住,忽略了真实的成绩。这样说不定还会赏你点东西,然后大笔一挥一签字,你也可以松一口气终于又混过一次了。其实这些东西都可

我们可以用一个简单的例子引出来装饰模式,在小的时候,相信大家都有过这样的经历:小学每年会有好几次的考试,如果有一次成绩非常差,而且考完以后学校会有个很损的招,就是打印出来成绩单,然后让家长签字。那么拿着这个成绩单,肯定是不会直接告诉家长成绩什么的,肯定是会加一些,例如,语文考了65,就会说我们班最高的才75。如果成绩单没有排名的话,那么也会添油加醋的说排名靠前,这样父母的就会被你说的所迷惑住,忽略了真实的成绩。这样说不定还会赏你点东西,然后大笔一挥一签字,你也可以松一口气终于又混过一次了。

其实这些东西都可以用类进行表示,类图如下

不学无数 — 装饰模式

SchoolReport 类如下

abstract class SchoolReport{
    public abstract void report();
    public abstract void sign(String name);
}

复制代码

FourGradesSchoolReport 类如下

class FourGradesSchoolReport extends SchoolReport{

    @Override
    public void report() {
        System.out.println("尊敬的家长您好:");
        System.out.println("您孩子的成绩如下: ");
        System.out.println("语文65 数学70 体育80");
    }

    @Override
    public void sign(String name) {
        System.out.println("家长签名: "+name);
    }
}

复制代码

Father 类如下

public static void main(String[] args) {
    SchoolReport schoolReport = new FourGradesSchoolReport();
    schoolReport.report();
    schoolReport.sign("张三");
}

复制代码

当然这是学习好的同学的做法,直接将成绩单展示给家长就好,像考的差的就得加上上面的修饰了。类图如下:

不学无数 — 装饰模式

上面的两个类不变,只是增加了修饰的类 SougarFourGradesSchoolReport 如下:

class SougarFourGradesSchoolReport extends FourGradesSchoolReport{

    private void reportHighScore(){
        System.out.println("这次考试语文最高成绩是75,数学最高是80");
    }

    private void reportSort(){
        System.out.println("我在班级排名是20");
    }

    public void report(){
    	  //先汇报最高的成绩
        this.reportHighScore();
        super.report();
        //然后汇报排名
        this.reportSort();
    }
}

复制代码

就会发现输出如下

这次考试语文最高成绩是75,数学最高是80
尊敬的家长您好:
您孩子的成绩如下: 
语文65 数学70 体育80
我在班级排名是20
家长签名: 张三

复制代码

直接通过继承 FourGradesSchoolReport 此类确实能解决现有的问题,但是现实情况是非常复杂的,如果是老爸当时喝多了直接看了成绩单就直接签字了、或者是听完汇报最高成绩以后就直接乐的直接签字了,后面排名啥的都不看了、又或者是老爸想先看排名怎么办?继续扩展?那会增加多少类?这还是一个比较简单的场景,如果需要装饰的条件非常多的话,那么每个条件都进行扩展的话,那么子类的数量会激增。而且后期维护也不好。

因此出现问题了,扩展性不好该怎么办?聪明的 程序员 们想到了一个办法,专门定义一批负责装饰的类,然后根据实际的情况进行组装装饰。类图如下:

不学无数 — 装饰模式

此时的 Decorator 类如下

abstract class Decorator extends SchoolReport{
    private SchoolReport schoolReport;
    
    public Decorator(SchoolReport schoolReport){
        this.schoolReport = schoolReport;
    }
    
     @Override
     public void report() {
        this.schoolReport.report();
     }

     @Override
     public void sign(String name) {
        this.schoolReport.sign(name);
     }
 }

复制代码

此时如果你了解代理模式的话,可能会有疑问,这和代理模式不是一样吗?带着这个疑问读下去。

此时的两个修饰类 HighSoreDecoratorSortDecorator 如下

class HighScoreDecorator extends Decorator{

    public HighScoreDecorator(SchoolReport schoolReport) {
        super(schoolReport);
    }

    private void reportHighScore(){
        System.out.println("这次考试语文最高成绩是75,数学最高是80");
    }

    public void report(){
        this.reportHighScore();
        super.report();
    }
}

class SortDecorator extends Decorator{

    public SortDecorator(SchoolReport schoolReport) {
        super(schoolReport);
    }

    private void reportSort(){
        System.out.println("我在班级排名是20");
    }

    public void report(){
        this.reportSort();
        super.report();
    }
}

复制代码

此时在调用的时候就可以进行随意的装饰,例如老爸想先听最高分,然后直接签名那么调用如下

public static void main(String[] args) {
    SchoolReport schoolReport;
    schoolReport = new FourGradesSchoolReport();
    schoolReport = new HighScoreDecorator(schoolReport);
    schoolReport.report();
    schoolReport.sign("张三");
}

复制代码

打印如下

这次考试语文最高成绩是75,数学最高是80
尊敬的家长您好:
您孩子的成绩如下: 
语文65 数学70 体育80
家长签名: 张三

复制代码

例如老爸想要先听排名,然后听最高成绩,最后签名,那么调用如下

public static void main(String[] args) {
    //成绩单拿过来
    SchoolReport schoolReport;
    //原装的成绩单
    schoolReport = new FourGradesSchoolReport();
    //加了最高分的成绩单
    schoolReport = new HighScoreDecorator(schoolReport);
    //加了成绩排名的成绩单
    schoolReport = new SortDecorator(schoolReport);
    schoolReport.report();
    schoolReport.sign("张三");
}

复制代码

打印如下

我在班级排名是20
这次考试语文最高成绩是75,数学最高是80
尊敬的家长您好:
您孩子的成绩如下: 
语文65 数学70 体育80
家长签名: 张三

复制代码

此时我们如果想增加其他的装饰模式,只需要继承了 Decorator 类即可,然后在使用的时候尽情组合就行。

装饰模式定义

装饰模式是动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更加灵活

装饰模式的通用类图如下

不学无数 — 装饰模式

在类图中有四种角色需要说明

  • Component :Component是一个接口或者是抽象类,即定义我们最核心的对象,也就是最原始的对象,如上面的成绩单 SchoolReport
  • ConcreateComponent :是最原始最基本的接口或者抽象类的实现,被装饰的对象
  • Decorator :一般是一个抽象类,实现接口或者抽象方法,它里面不一定有抽象的方法,但是它的属性中必然有一个private变量指向 Component 抽象构件
  • ConcreteDecoratorAConcreteDecoratorB :两个具体的装饰类,在里面需要写所想装饰的东西。

那么接下来看装饰类通用的实现

Component

abstract class Component{
    public abstract void operate();
}

复制代码

具体的实现类 ConcreateComponent

class ConcreateComponent extends Component{
    @Override 
    public void operate() {
        System.out.println("do something");
    }
}

复制代码

抽象的装饰类 Decorator

abstract class Decorator extends Component {
    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operate() {
        this. component. operate();
    }
}

复制代码

具体的装饰类 ConcreteDecoratorAConcreteDecoratorB

class ConcreteDecoratorA extends Decorator{

    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    private void methodA(){
        System.out.println("MethodA装饰");
    }
    
    public void operate(){
        this.methodA();
        super.operate();
    }
}

class ConcreteDecoratorB extends Decorator{

    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    private void methodB(){
        System.out.println("MethodB装饰");
    }
    
    public void operate(){
        this. methodB();
        super.operate();
    }
}

复制代码

此处需要主要原始方法和装饰方法的执行顺序在具体的装饰类中时固定的,如果想要不同的顺序可以通过重载实现多种执行顺序。

装饰模式的优缺点

优点

  • 装饰类和被装饰类可以独立发展,不会相互耦合,换句话说, Component 类无需知道 Decorator 的类, Decorator 类是从外部来扩展 Component 类的功能。
  • 装饰模式是继承关系的一个替代方案,我们可以看到在装饰类中 Decorator 无论装饰了多少层,返回的对象还是 Component
  • 装饰模式可以动态的扩展一个实现类的功能

缺点

只需要记住一点就好: 复杂

装饰模式和代理模式的区别

相信前面看完了装饰模式会对装饰模式有个简单的理解,装饰模式以对客户透明的方式扩展对象功能,主要凸显的是修饰、增加功能

而代理模式是给对象提供一个代理对象,并由代理对象来控制原有对象的引用,主要凸显是控制功能。

参考文章


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算理论导论

计算理论导论

塞普斯 / 机械工业出版社 / 2002-8 / 39.0

This book——by a noted authority and educator in the field——presents computer science theory from a uniquely intuitive,“big picture”perspective.The author grounds his clear and interesting study on ......一起来看看 《计算理论导论》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具