欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

非常一个有意思的设计模式--装饰模式

程序员文章站 2024-03-17 20:34:28
...

  本文的主体是装饰模式,那么什么是装饰模式呢?在谈这个概念之前先给广大女朋友(理论上来说,所有未婚女性都有可能是我女朋友)送波礼物:

  收礼物应该是女同胞的最爱了,作为一个女孩子,肯定希望自己的男朋友可以给足惊喜。我知道很多男人是没有办法创造这种浪漫的氛围的,好吧,小林代劳了,送女孩子们一个礼物,大大的爱心!

非常一个有意思的设计模式--装饰模式

  通过图我们可以很清晰的看到,红色盒子装着蓝色盒子,蓝色盒子又装着绿色盒子。绿色的盒子里装着我们的小心心。那么我们的小心心是不是就被装饰起来了呢?用绿色盒子装饰小心心,用蓝色盒子装饰绿色盒子,用红色盒子装饰蓝色盒子。看个图会更清晰!

非常一个有意思的设计模式--装饰模式

  小林的一号女朋友收到礼物后非常的不满意,我不喜欢这种颜色嵌套,你把盒子的颜色倒过来我才喜欢。小林二话不说马上动手,十分钟小林的礼物变成这样:

非常一个有意思的设计模式--装饰模式

  一号女朋友收到礼物后非常的开心,小林决定再做一份同样的礼物送给二号女朋友,说时迟那是快,直接送到二号女朋友脸前。二号女朋友打开礼物后,非常的不高兴,你不知道我喜欢深一点吗,为什么就套三个盒子,给我多套几个!小林为了满足二号女朋友修改了一下礼物,变成这样:

非常一个有意思的设计模式--装饰模式

  二号女朋友一看是非常的开心那,我就喜欢这么深的礼物。

  我们来分析一下小林送礼物的整个流程。首先我们会看到不管是那种方式的哪一步,都会有一个同样的东西,那就是红心。而我们**在红心外面套盒子是为了让红心更漂亮,至于盒子怎么套,套几个是不是可以控制的呢?**对的,这就是我们说的装饰,装饰就是在原来的基础上去增加一些修饰性的东西。相信到此,大家对装饰已经有了明确的概念。接下来用《大话设计模式》中的案例来学习一下。

用户故事:我想要一个客户可以随意搭配服饰的装饰系统

完成这个系统我们需要有:

  1. 要有一个客户类,用于被修饰
  2. 要有很多的服装,供用户*搭配

具体案例分析

第一版代码

@Data
public class Person {
    // 名字
    private String name;

    public Person(String name){
        this.name=name;
    }

    public void wearTShirts(){
        System.out.print("大T恤 ");
    }

    public void wearBigTrouser(){
        System.out.print("垮裤 ");
    }

    public void wearSneakers(){
        System.out.print("破球鞋 ");
    }

    public void wearSuit(){
        System.out.print("西装 ");
    }

    public void wearTie(){
        System.out.print("领带 ");
    }

    public void wearLeatherShoes(){
        System.out.print("皮鞋 ");
    }

    public void show(){
        System.out.println("装扮的" + name);
    }
}
public class MainTest {
    public static void main(String[] args) {
        Person xiaoLin = new Person("小林");
        xiaoLin.wearTie();
        xiaoLin.wearBigTrouser();
        xiaoLin.wearSuit();
        xiaoLin.show();
    }
}

  首先看一下UML类图(现在大家对着代码应该能看的懂,后期后专门出一篇讲UML),非常简单就一个类,但是它是否存在问题呢?

非常一个有意思的设计模式--装饰模式

  这个代码实现了功能,但是却把各种服饰放到了一个类中,这就违背了开发中的单一职责原则(这个类一个职责是创建一个人,另一个职责是可以穿各种各样的服饰)。这还不是最主要的,如果以后每加一个服饰,那么就要打开这个类修改,这又违反了开发中的开闭原则,尽管不可能完全的对修改关闭,但是也要尽量去遵循这个原则。这个时候原则大家可以想想如何修改第一版代码,使其可以满足单一职责跟开闭原则。

第二版代码

  首先看下第二版代码的UML类图,这样会不会清晰很多,首先Person跟服饰分开了,并且将服饰抽象成一个类,具体的服装都来实现这个服饰类,这样新加一些服饰,直接写一个类继承服饰类即可,这样我们就达到了对修改关闭,对扩展开放的原则。但是我还是要说现在代码还是可优化的,具体如何优化,各位看官看完下面的代码可以思考一下!

非常一个有意思的设计模式--装饰模式

public class Person {
    private String name;

    public Person(String name){
        this.name = name;
    }

    public void show(){
        System.out.println("装扮的" + name);
    }
}
public abstract class Finery {
    abstract void show();
}
public class BigTrouser extends Finery {
    @Override
    void show() {
        System.out.print("垮裤 ");
    }
}

public class LeatherShoes extends Finery {
    @Override
    void show() {
        System.out.print("皮鞋 ");
    }
}

public class Sneakers extends Finery {
    @Override
    void show() {
        System.out.print("破球鞋 ");
    }
}

public class Suit extends Finery {
    @Override
    void show() {
        System.out.print("西装 ");
    }
}

public class Tie extends Finery {
    @Override
    void show() {
        System.out.print("领带 ");
    }
}

public class TShirts extends Finery {
    @Override
    void show() {
        System.out.print("大T恤 ");
    }
}
public class MainTest {
    public static void main(String[] args) {
        Person xiaoLin = new Person("小林");
        Finery suit = new Suit();
        Finery bigTrouser = new BigTrouser();
        Finery tshirts = new TShirts();
        suit.show();
        bigTrouser.show();
        tshirts.show();
        xiaoLin.show();
    }
}

第三版代码

​   我们发现在main里面我们的是这么写的,suit.show(),bigTrouser.show(),调用者都是不一样的。这样相当于我们在穿衣服的过程中是暴露的,你穿衣服的过程都让人尽收眼底。所以这样是不太合适的,我们应该是**将衣服在内部全部穿好,然后进行展示。**我们来看下UML图
非常一个有意思的设计模式--装饰模式

public class Person {
    private String name;

    public Person(){

    }

    public Person(String name){
        this.name = name;
    }

    public void show(){
        System.out.println("装扮的" + name);
    }
}
public class Decorator extends Person {

    protected Person component;

    public void decorate(Person component){
        this.component = component;
    }

    @Override
    public void show() {
        if (component != null){
            component.show();
        }
    }
}
public class BigTrouser extends Decorator {
    @Override
    public void show() {
        System.out.print("垮裤 ");
        super.show();
    }
}

public class LeatherShoes extends Decorator {
    @Override
    public void show() {
        System.out.print("皮鞋 ");
        super.show();
    }
}

public class Sneakers extends Decorator {
    @Override
    public void show() {
        System.out.print("破球鞋 ");
        super.show();
    }
}

public class Suit extends Decorator {
    @Override
    public void show() {
        System.out.print("西装 ");
        super.show();
    }
}

public class Tie extends Decorator {
    @Override
    public void show() {
        System.out.print("领带 ");
        super.show();
    }
}

public class TShirts extends Decorator {
    @Override
    public void show() {
        System.out.print("大T恤 ");
        super.show();
    }
}

  接下来看看控制台代码如何写,首先创建穿衣服的人xiaoLin,接下来就是new几个具体服饰对象,sneakers,bigTrouser,tShirts,然后最重要是decorate()方法,这个方法传入的Person对象,然后在Decorator类中维护一个Person对象。然后将通层层包装,将具体服饰对象一层一层的包装,由最后一个对象tShirts调用一次show方法即可,不必像第二版代码一样调用了四次show方法。

tips:可能有小伙伴不明白为什么具体服饰对象可以传进decorate()方法,原因很简单,因为具体服饰类的的爹的爹是Person,可以结合上面的UML图看。

public class MainTest3 {
    public static void main(String[] args) {
        Person xiaoLin = new Person("小林");
        Sneakers sneakers = new Sneakers();
        BigTrouser bigTrouser = new BigTrouser();
        TShirts tShirts = new TShirts();
        sneakers.decorate(xiaoLin);
        bigTrouser.decorate(sneakers);
        tShirts.decorate(bigTrouser);
        tShirts.show();
    }
}

Sneakers sneakers = new Sneakers();
BigTrouser bigTrouser = new BigTrouser();
TShirts tShirts = new TShirts();
sneakers.decorate(xiaoLin);
bigTrouser.decorate(sneakers);
tShirts.decorate(bigTrouser);
tShirts.show();
}
}