【设计模式】结构型-装饰器模式

我比较喜欢吃红烧牛肉面,因为牛肉味道鲜美,能长肌肉,不发胖,尤其我们这里的杨记拉面更是一绝。没有吃过的同学们可以来我大河南尝一尝~哈哈不是打广告哈,是真的好吃~呦呵,服务员立马给我端上一碗拉面:

public class Noodles {
    public void show() {
        System.out.println("红烧牛肉面");
    }
}

嗯,突然觉得仅吃牛肉面我觉得还不够,想在面里加个鸡蛋怎么办?这不简单吗?我继承面条类,扩展出一个加鸡蛋的子类不就行了?!

public class EggNoodles extends Noodles {
    @Override
    public void show() {
        System.out.println("加了鸡蛋");
        super.show();
    }
}

身边的孩子看到我加了鸡蛋,他也想加点什么。“爸爸,我想加块卤豆腐干!”“好嘞,服务员给小孩的这碗加个豆干~”

public class TofuNoodles extends Noodles {
    @Override
    public void show() {
        System.out.println("加了豆腐干");
        super.show();
    }
}

媳妇一看,“你们都加东西了,不行我也要加,我要面里加鸡蛋和豆干!”

public class EggTofuNooles extends Noodles {
    @Override
    public void show() {
        System.out.println("加了鸡蛋和豆腐干");
        super.show();
    }

}

至此,我们一家三口吃的津津有味~

public class Main {
    public static void main(String[] args) {
        EggNoodles eggNoodles = new EggNoodles();
        eggNoodles.show();

        TofuNoodles tofuNoodles = new TofuNoodles();
        tofuNoodles.show();

        EggTofuNooles eggTofuNooles = new EggTofuNooles();
        eggTofuNooles.show();
    }
}

人饿的时候满脑子都是吃的,吃饱了之后大脑就有精神了,我越想越不对。这面里如果同时加了鸡蛋和豆腐干就要扩展一个子类出来,那如果有的人单独加香菜加香菜,鸡蛋,豆腐干加香菜,鸡蛋。。。。这组合起来可多的去了,类就要爆炸了呀!而且我们的设计违反了开闭原则,虽然通过继承实现了对扩展开放,但是我们对父类就是面条类覆写了show方法,即对修改开放了。而且我们的面条不应该设计为具体的类,应该是抽象或者接口,以便日后可以扩展出其他面出来。重新梳理之后,发现装饰器模式非常适合这样的场景,我们就来改造下。

首先建立面条接口(组件接口)以及其实现类(具体组件)

public interface Noodles {
    void show();
}

public class BeefNoodles implements Noodles {
    @Override
    public void show() {
        System.out.println("红烧牛肉面");
    }
}

我们把面条抽象成接口,这样的话以后什么面条都不怕了,饸烙面,烩面,山西刀削面。。。

建立抽象装饰者(实现组件接口)以及其不同的实现类

public abstract class AbstractDecorator implements Noodles {
    protected Noodles noodles;
    public AbstractDecorator(Noodles noodles) {
        this.noodles = noodles;
    }
}

public class EggDecorator extends AbstractDecorator {
    public EggDecorator(Noodles noodles) {
        super(noodles);
    }

    @Override
    public void show() {
        System.out.println("加了鸡蛋");
        this.noodles.show();
    }

}

public class TofuDecorator extends AbstractDecorator {
    public TofuDecorator(Noodles noodles) {
        super(noodles);
    }

    @Override
    public void show() {
        System.out.println("加了豆腐干");
        this.noodles.show();
    }
}

到这里你会问,那加豆腐干和鸡蛋的怎么办?也建个对应的装饰类?根本没必要,就一句话搞定,直接省了一个类。我们来看客户端代码:

public class Main {
    public static void main(String[] args) {
        Noodles noodles = new BeefNoodles();

        AbstractDecorator eggDecorator = new EggDecorator(noodles);
        eggDecorator.show();

        AbstractDecorator tofuDecorator = new TofuDecorator(noodles);
        tofuDecorator.show();

        AbstractDecorator egg_tofuDecorator = new EggDecorator(tofuDecorator);
        egg_tofuDecorator.show();
    }
}

先用TofuDecorator装饰,然后再用EggDecorator装饰就完了~是不是省个类?那我再加个香菜无非就是再用香菜的装饰一下而已。

Java,C++等语言有抽象类,这样我们就可以方便的把构造函数和Noodles接口成员变量提前写好了。像GO语言就没有抽象类,只能用接口了。

总结:

装饰器模式解决了类爆炸的问题,它对比直接继承符合了开闭原则,因为它没有修改父类的方法。而它是解决的扩展问题,核心功能保持不变,符合单一原则,即红烧牛肉面就是红烧牛肉面,无论加了多少配菜,核心是拉面。在真实的应用场景中,中间件技术很多都是用了装饰器模式,还有JDK的InputStream体系也是使用了该模式。如果说,要扩展的功能非常多,那么这样的情况应该去思考是不是自己设计的类出现了问题,而不是直接使用该模式了,所以具体的情况要具体分析。

最后给出GOF对装饰器模式的定义:允许向一个现有的对象添加新的功能,同时又不改变其结构。

demo地址:GitCode - 全球开发者的开源社区,开源代码托管平台

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Diros2025

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值