java实现装饰器模式(Decorator Pattern)

Java实现装饰器模式

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许我们动态地将行为添加到某个对象中,而不是通过继承来实现。它是在保持类方法签名不变的情况下增加功能,实现类的功能扩展。

角色介绍

  • Component:抽象组件,定义装饰者和被装饰者的最基本的接口和规范。
  • ConcreteComponent:具体组件,也是被装饰器装饰的基本对象,实现抽象组件中的方法。
  • Decorator:抽象装饰器,实现了Component接口,并且持有一个被装饰者的引用。旨在为后续的具体装饰器提供代理或者委托相应的行为扩展。
  • ConcreteDecorator:具体装饰器,继承Decorator,重写接口中的方法,完成相应的装饰逻辑。

示例1:文字消息发送功能

我们需要设计一个具有文字消息发送能力的聊天应用,但是仅仅有文字消息发送的聊天,显然这个应用并不太好用。所以,我们需要实现添加表情和图片消息的功能。

我们可以将文字消息发送功能抽象为一个Component类,即AbstractMessageSender类,然后定义三个装饰器:EmoticonMessageSender、PictureMessageSender和RedPacketMessageSender,分别用于装饰Component类,实现添加表情、图片和红包消息的功能。

public abstract class AbstractMessageSender {
    public abstract void sendMessage();
}

public class TextMessageSender extends AbstractMessageSender {
    @Override
    public void sendMessage() {
        System.out.println("发送了一条文字消息");
    }
}

public abstract class MessageSenderDecorator extends AbstractMessageSender {
    protected AbstractMessageSender messageSender;

    public MessageSenderDecorator(AbstractMessageSender messageSender) {
        this.messageSender = messageSender;
    }

    public void sendMessage() {
        messageSender.sendMessage();
    }
}

public class EmoticonMessageSender extends MessageSenderDecorator {
    public EmoticonMessageSender(AbstractMessageSender messageSender) {
        super(messageSender);
    }

    @Override
    public void sendMessage() {
        super.sendMessage();
        System.out.println("带有表情的消息");
    }
}

public class PictureMessageSender extends MessageSenderDecorator {
    public PictureMessageSender(AbstractMessageSender messageSender) {
        super(messageSender);
    }

    @Override
    public void sendMessage() {
        super.sendMessage();
        System.out.println("带有图片的消息");
    }
}

public class RedPacketMessageSender extends MessageSenderDecorator {
    public RedPacketMessageSender(AbstractMessageSender messageSender) {
        super(messageSender);
    }

    @Override
    public void sendMessage() {
        super.sendMessage();
        System.out.println("带有红包的消息");
    }
}

使用示例代码:

AbstractMessageSender textMessageSender = new TextMessageSender();
textMessageSender = new EmoticonMessageSender(textMessageSender);
textMessageSender = new PictureMessageSender(textMessageSender);
textMessageSender = new RedPacketMessageSender(textMessageSender);
textMessageSender.sendMessage();

运行结果为:

发送了一条文字消息
带有表情的消息
带有图片的消息
带有红包的消息

示例2:饮料点单系统

我们现在要实现一个简单的点单系统,基础饮料有红茶、绿茶和奶茶,但是用户可以选择加入椰果、芋头、珍珠等等不同口味的配料。这些配料是新增的,我们不希望因为新的加入而修改原本的代码,更好的方法是采用装饰器模式。

我们定义一个抽象类Beverage,表示基础饮料。具体的基础饮料类RedTea、GreenTea和MilkTea实现Beverage接口,然后配料类可以继承或实现Beverage接口,形成装饰器类Milk、Pearl、Coconut等。

public abstract class Beverage {
    protected String name;

    public String getName() {
        return name;
    }

    public abstract double cost();
}

public class RedTea extends Beverage {
    public RedTea() {
        super.name = "红茶";
    }

    public double cost() {
        return 10;
    }
}

public class GreenTea extends Beverage {
    public GreenTea() {
        super.name = "绿茶";
    }

    public double cost() {
        return 8;
    }
}

public class MilkTea extends Beverage {
    public MilkTea() {
        super.name = "奶茶";
    }

    public double cost() {
        return 12;
    }
}

public abstract class CondimentDecorator extends Beverage {
    protected Beverage beverage;

    public abstract String getName();

    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }
}

public class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) {
        super(beverage);
    }

    public String getName() {
        return beverage.getName() + " 加牛奶";
    }

    public double cost() {
        return 2.5 + beverage.cost();
    }
}

public class Pearl extends CondimentDecorator {
    public Pearl(Beverage beverage) {
        super(beverage);
    }

    public String getName() {
        return beverage.getName() + " 加珍珠";
    }

    public double cost() {
        return 3.5 + beverage.cost();
    }
}

public class Coconut extends CondimentDecorator {
    public Coconut(Beverage beverage) {
        super(beverage);
    }

    public String getName() {
        return beverage.getName() + " 加椰果";
    }

    public double cost() {
        return 3 + beverage.cost();
    }
}

使用示例代码:

Beverage redTea = new RedTea();
System.out.println(redTea.getName() + ",价格:" + redTea.cost());

Beverage milkWithGreenTea = new Milk(new GreenTea());
System.out.println(milkWithGreenTea.getName() + ",价格:" + milkWithGreenTea.cost());

Beverage pearlWithMilkTea = new Pearl(new MilkTea());
System.out.println(pearlWithMilkTea.getName() + ",价格:" + pearlWithMilkTea.cost());

Beverage coconutWithGreenWithMilkTea = new Coconut(new Milk(new GreenTea()));
System.out.println(coconutWithGreenWithMilkTea.getName() + ",价格:" + coconutWithGreenWithMilkTea.cost());

运行结果为:

红茶,价格:10.0
绿茶 加牛奶,价格:10.5
奶茶 加珍珠 加牛奶,价格:18.5
绿茶 加牛奶 加椰果,价格:13.5

总结

装饰器模式通过组合的方式,动态地实现增加属性和功能,同时也保证了被装饰器装饰的原对象不会被修改,这种方式增强扩展性更好。但是如果装饰器的嵌套层数过深,可能会影响代码阅读的效率。在设计模式的选择上,应根据具体的需求和情况来进行考虑。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java实现装饰器模式(Decorator Pattern) - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • bootstrap weebox 支持ajax的模态弹出框

    Bootstrap是一套UI框架,其中Weebox是一个基于Bootstrap的模态弹出框插件,支持AJAX加载内容。本攻略将详细介绍如何使用Bootstrap Weebox插件实现AJAX加载内容的模态弹出框。 准备工作 引入Bootstrap和jQuery库。 <link rel="stylesheet" href="…

    Java 2023年6月16日
    00
  • 浅谈Maven Wrapper

    关于如何使用 Maven Wrapper,我这里提供一份完整攻略,包含以下内容: 什么是 Maven Wrapper Maven Wrapper 是 Maven 内置的一个小型 Maven 版本管理工具,是 Maven 3.5.0 版本中引入的新特性。它的主要作用是帮助使用者对 Maven 进行版本控制,防止出现版本不一致的问题。使用 Maven Wrapp…

    Java 2023年6月2日
    00
  • Java实时监控日志文件并输出的方法详解

    Java实时监控日志文件并输出的方法,可以使用Java IO和多线程的知识来完成。主要流程可以分为以下几步: 创建一个文件读取器,用于读取日志文件的内容。 定义一个线程类,用于不断读取文件内容,并输出到控制台或其他存储介质中。 开启线程,开始实时监控日志文件。 具体实现步骤如下: 1、创建一个文件读取器 使用Java IO中的FileReader和Buffe…

    Java 2023年5月26日
    00
  • JSP由浅入深(7)—— JSP Directives

    JSP Directives 是 JSP 中的一种特殊指令,用于控制 JSP 引擎的行为,并支持在 JSP 编译和执行过程中的各种操作。下面将通过实例,详细讲解 JSP Directives 的使用方法。 基本语法 JSP 中的 Directives 以 <%@ 开头,以 %> 结尾,其中 % 与 < 和 @ 之间不能有空格。 下面是 JS…

    Java 2023年6月15日
    00
  • 在jsp页面如何获得url参数

    在JSP页面中,我们可以通过request对象获取URL参数。下面是获取URL参数的完整攻略: 在JSP页面中使用request对象获取URL参数 我们可以通过request.getParameter()方法来获取请求中的特定参数。 示例1: 获取单个参数值 假设我们有一个URL http://www.example.com/index.jsp?name=J…

    Java 2023年6月15日
    00
  • SpringBoot多数据源的两种实现方式实例

    下面我就为你详细讲解一下“SpringBoot多数据源的两种实现方式实例”的完整攻略。 SpringBoot多数据源的两种实现方式实例 为什么需要多数据源 在实际开发中,我们可能会遇到这样的情况:业务系统需要同时连接多个数据库进行数据操作。此时单数据源的方式已无法满足需求,必须使用多数据源来进行解决。 方案一:使用@Primary注解 1.添加多数据源配置项…

    Java 2023年5月20日
    00
  • MIME Base64编码

    Base64是一种用于将二进制数据编码成可打印ASCII字符的编码方式。它由64个字符组成,包括A-Z、a-z、0-9以及+和/。它的编码规则非常简单:将3个字节的二进制数据(共24位)分成4组,每组6位,然后将这4组6位的值转换成一个可打印ASCII字符。 MIME Base64是Base64的一种变体,它是Multipurpose Internet Ma…

    Java 2023年4月25日
    00
  • 用JavaScript和注册表脚本实现右键收藏Web页选中文本

    为了实现右键收藏Web页选中文本的功能,我们需要使用JavaScript和注册表脚本。 步骤如下: 创建一个新的注册表脚本文件,将其保存为 .reg 文件类型。 Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\Collect] @="收藏选中文本" [HKEY…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部