为了账号安全,请及时绑定邮箱和手机立即绑定

装饰模式:给对象动态加新功能的技巧

标签:
设计模式
装饰器模式到底是什么呢?

装饰器模式是一种结构型设计模式,它通过动态地为对象添加额外的行为来扩展对象的功能。装饰器通过组合而不是继承,提供了更加灵活的扩展方法。

什么时候用它?

当你希望在运行时通过添加行为来构建对象时,请使用装饰模式。

UML图

图片说明 "点击这里查看图片"

装饰器类使用组合和继承,理解这点很重要。
在装饰器模式里,我们对组件和装饰器使用相同类型。装饰器通过组合组件对象来获取行为,即获取组件对象中的字段或方法。而装饰器继承组件(即扩展),使得装饰器对象可以当作组件对象使用。

装饰器模式实现了开闭原则,即对扩展开放,对修改关闭。添加组件或装饰器十分简单。例如,如果你想添加另一个具体的装饰器,你只需创建一个表示它的类,并继承装饰器类。

例子

想象我们正在为一家冰淇淋店建立一个系统。这家店有各种口味的冰淇淋和 topping。系统需要显示每份冰淇淋的描述(包括顶部的配料)及其成本。

图片描述 这是一张图片。

  • 冰淇淋成分和配料都使用共同的 IceCream 接口,它们都被声明为 IceCream 对象。
  • 每种具体的冰淇淋都重写了 cost 方法,因为每种冰淇淋的价格各不相同。
  • Topping 类提供了具体配料的接口,并引用一个 IceCream 对象。
  • 如果系统需要另一种配料,例如焦糖酱,你只需要创建一个继承自 Topping 类的 CaramelSource 类即可。
用Java实现的

IceCream 类:

    // 表示冰激凌的抽象类
    public abstract class IceCream {

        public String description = "未知的冰激凌";

        public String getDescription() {
            return description;
        }

        public abstract double price();
    }

全屏 全屏退出

巧克力冰激凌类:

// 具体类
public class ChocolateIceCream extends IceCream {

    public ChocolateIceCream() {
        this.description = "巧克力冰淇淋";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}

点击全屏,点击退出全屏

最棒的课程:

    // 基础装饰类
    public abstract class Topping extends IceCream {

        public IceCream iceCream;

        // 所有子类(具体装饰类)需要实现 getDescription 方法,
        // 通过将其声明为抽象方法,我们要求所有子类实现此方法
        public abstract String getDescription();
    }

切换到全屏 退出全屏

MapleNuts 类:

// 具体装饰类
public class MapleNuts extends Topping { // 继承自装饰层父类

    public MapleNuts(IceCream iceCream) {
        this.iceCream = iceCream;
    }

    @Override
    public String getDescription() {
        return iceCream.getDescription() + ", MapleNuts"; // 添加枫糖坚果
    }

    @Override
    public double cost() {
        return iceCream.cost() + .30; // 计算成本
    }
}

全屏 退出全屏

PeanutButterShell 类:

    // 具体的装饰类
    public class PeanutButterShell extends Topping {

        public PeanutButterShell(IceCream iceCream) {
            this.iceCream = iceCream;
        }

        @Override
        public String getDescription() {
            return iceCream.getDescription() + ", 加上花生壳酱";
        }

        @Override
        public double cost() {
            return iceCream.cost() + .30; // 增加0.30元
        }
    }

全屏模式,退出全屏模式

客户端类(Client 类):

    public class 客户 {

        public static void main(String[] args) {
            冰淇淋 iceCream = new 巧克力冰淇淋();
            System.out.println("描述:" + iceCream.getDescription() + ",价格:" + iceCream.cost() + "元");

            iceCream = new 枫糖坚果(iceCream);
            System.out.println("描述:" + iceCream.getDescription() + ",价格:" + iceCream.cost() + "元");

            iceCream = new 花生酱壳冰淇淋(iceCream);
            System.out.println("描述:" + iceCream.getDescription() + ",价格:" + iceCream.cost() + "元");
        }
    }

点击全屏 点击退出全屏

输出:

巧克力冰激凌,1.99美元
加枫坚果的巧克力冰激凌,2.29美元
加枫坚果和花生壳的巧克力冰激凌,2.59美元

切换到全屏,切换回正常模式

……

这里可以查看所有设计模式的实现。
GitHub仓库链接


附注:
我是新手写技术博客,如果有任何关于写作的建议,或者有任何不明白的地方,请在下面评论!
谢谢大家的阅读 :)

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消