不学无数——装饰模式

装饰模式

在开始以前

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

其实这些东西均可以用类进行表示,类图以下设计模式

成绩报告图

SchoolReport 类以下ide

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类以下this

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

固然这是学习好的同窗的作法,直接将成绩单展现给家长就好,像考的差的就得加上上面的修饰了。类图以下:.net

通过修饰的类图

上面的两个类不变,只是增长了修饰的类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();
    }
}

就会发现输出以下3d

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

直接经过继承FourGradesSchoolReport此类确实能解决现有的问题,可是现实状况是很是复杂的,若是是老爸当时喝多了直接看了成绩单就直接签字了、或者是听完汇报最高成绩之后就直接乐的直接签字了,后面排名啥的都不看了、又或者是老爸想先看排名怎么办?继续扩展?那会增长多少类?这仍是一个比较简单的场景,若是须要装饰的条件很是多的话,那么每一个条件都进行扩展的话,那么子类的数量会激增。并且后期维护也很差。代理

所以出现问题了,扩展性很差该怎么办?聪明的程序员们想到了一个办法,专门定义一批负责装饰的类,而后根据实际的状况进行组装装饰。类图以下:code

通过改进的类图

此时的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
  • 装饰模式能够动态的扩展一个实现类的功能

缺点

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

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

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

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

参考文章

相关文章
相关标签/搜索