前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >装饰器模式:如何用Java打扮一个对象?

装饰器模式:如何用Java打扮一个对象?

原创
作者头像
你被录用了
修改2025-03-30 02:17:49
修改2025-03-30 02:17:49
480
举报
文章被收录于专栏:设计模式设计模式

引言

在生活中,我们都知道一句话,“人靠衣装马靠鞍”,如果想要让自己在别人眼里看起来更加好看,更加丰富多彩,就得要学会打扮自己,为自己化妆,为自己穿好看的衣服,学会了打扮的本领,那么我们就可以轻松应对不同场合的需求。无论是日常通勤的简约风,还是晚宴的华丽造型,我们只需在“基础自我”上叠加不同的装饰元素,而无需改变本质——这种灵活性和可扩展性,恰恰是装饰器模式(Decorator Pattern) 在软件设计中的精髓。

想象一下,我们在实际生活中,是不是如果当前的脸上瑕疵较多,就使用素颜霜遮盖一下,当前的皮肤太黑,也可以通过化妆技术变白。穿衣更是如此,我们可以选择穿简约风格的衣服,在得知今晚要参加晚宴后,还可以换上一套隆重的礼服。这些操作都不需要我们变成一个新的人(继承的方法),只需要我们使用一下化妆或者是换装的方法就可以(装饰器的方法)。

本文通过对一个男孩打扮和换装的例子,来深入了解装饰器模式。

装饰器模式

装饰器模式是一个结构性设计模式,允许在不修改原有类的情况下,为对象动态添加新功能,而不会影响其他对象。通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。针对目标方法进行增强,提供新的功能或者额外的功能。也就是例子中的我们把需要打扮的男孩放到化妆台前或者是衣柜前,然后这个男孩回来的时候就是一个打扮过的了,比原来更加丰富多彩。

首先看一下装饰器模式的四大核心组件:

Component: 所有可以被装饰的类要继承的接口,同时,装饰器类也要继承该接口,这样可以保证装饰前的对象和经过装饰后返回的对象是同一个类型。

ConcreteComponent: 具体要装饰的类,实现Component接口,实现被装饰前的方法。

AbstractDecorator: 抽象装饰器类,同样实现AbstractDecorator接口,为什么要有这个抽象类呢?其实就是可以在这个抽象类中提前把被装饰的对象原始的功能实现,这样具体的装饰器类就不用每个都重复实现原本被装饰前的对象的功能了,只需要关注如何装饰它。

ConcreteDecorator: 具体的装饰器类,继承抽象装饰器类,它需要装饰的那个对象的原来的方法已经在抽象装饰器中实现了,所以这个类只需要关注需要对被装饰的类做出哪些装饰就行了。

具体实例

本文设计的例子是对一个男孩进行打扮,通过化妆台(化妆装饰器 MakeupDecorator)和衣帽间(DressupSimpleDecoratorDressupGrandDecorator )对男孩进行两次装饰,最终男孩原本的模样(方法)变成装饰后的模样。

共有接口类

所有可以被装饰的类都要继承这个接口。

代码语言:java
复制
//可以进行装饰需要满足的接口
interface PersonComponent{
    public String getFace();
    public String getColor();
    public String getDressed();
}

具体被装饰类

男孩需要被打扮,所以它实现上面的WaitForDecorator接口。

代码语言:java
复制
//等待被装饰的类
class Boy implements PersonComponent{
    String face;
    String color;
    String dress;

    @Override
    public String getFace() {
        return "ugly";
    }

    @Override
    public String getColor() {
        return "black";
    }

    @Override
    public String getDressed() {
        return "naked";
    }
}

抽象装饰器类

所有的具体装饰器类都要继承该接口,可以避免重复的代码多次编写,将需要被装饰的对象在这个抽象装饰器类中将原本的功能实现一遍,这样具体装饰器类就只需要关注具体需要装饰的功能了。

代码语言:java
复制
//装饰器基类
abstract class PersonDecorator implements PersonComponent{
    private People people;
    public PeopleDecorator(People people){
        this.people=people;
    }
    @Override
    public String getFace(){
        return people.getFace();
    }
    @Override
    public String getColor(){
        return people.getColor();
    }

    @Override
    public String getDressed(){
        return people.getDressed();
    }
}

具体装饰器类

化妆装饰器:

代码语言:java
复制
class MakeupDecorator extends PersonDecorator{
    public MakeupDecorator(People people) {
        super(people);
    }
    @Override
    public String getFace(){
        return "make ugly to pretty";
    }

    @Override
    public String getColor(){
        return "make black to white";
    }
}

简约风衣着装饰器:

代码语言:java
复制
class DressupSimpleDecorator extends PersonDecorator{
    public DressupSimpleDecorator(People people) {
        super(people);
    }

    public String getDressed(){
        return "wearing simple cloth";
    }
}

宴会衣着装饰器:

代码语言:java
复制
class DressupGrandDecorator extends PersonDecorator{

    public DressupGrandDecorator(People people) {
        super(people);
    }

    public String getDressed(){
        return "wearing grand cloth";
    }

}

测试

代码语言:java
复制
public static void main(String[] args) {
        PersonComponent boy =new Boy();
        //男孩先穿了简约衣服打算出门吃海底捞
        boy = new DressupSimpleDecorator(boy);
        //男孩简单地化了个妆
        boy = new MakeupDecorator(boy);
        //男孩突然被通知需要参加一场宴会,就换上了华丽的衣服。
        boy = new DressupGrandDecorator(boy);
        System.out.println(boy.getColor());
        System.out.println(boy.getFace());
        System.out.println(boy.getDressed());
    }

运行结果如下:

代码语言:java
复制
make black to white
make ugly to pretty
wearing grand cloth

可以看见男孩化了妆并且变得漂亮了,最后穿上的是后来穿的华丽衣服。

装饰器模式的实际应用

下面列举了几个典型的应用场景:

Java I/O 体系

Java 的 I/O 类库大量使用了装饰器模式,例如 BufferedReader、InputStreamReader、FileInputStream 等,允许开发者通过不同的装饰器动态增强流的功能。

代码语言:java
复制
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("data.txt")));

这里,BufferedReader 作为装饰器,增强了 InputStreamReader,提供了缓存功能以提高读取效率。其中他们的共同接口是Reader。

游戏开发中的角色装备系统

在游戏开发中,角色装备(如盔甲、武器)通常使用装饰器模式。例如,一个基础角色可以通过不同装备来增强属性,如增加攻击力、防御力等。

代码语言:java
复制
Character warrior = new Warrior();
warrior = new ArmorDecorator(warrior);  // 增加防御
warrior = new SwordDecorator(warrior);  // 增加攻击力

总结

装饰器模式通过“动态增强”而非“本质改变”的设计理念,为软件设计提供了高度的灵活性和可扩展性。本文以生活中“换装打扮”的生动场景为引,巧妙类比了装饰器模式的核心思想——在不修改对象自身的基础上,通过层层叠加装饰器来扩展功能。

核心价值体现:

灵活组合,动态扩展

如同男孩可根据场合自由切换妆容和服饰,装饰器模式允许在运行时动态添加或替换功能。例如,先穿简约服装,再化妆,最后换宴会礼服,每一步装饰都独立且可逆,避免继承带来的僵化性。

职责分离,结构清晰

通过抽象装饰器(PeopleDecorator)封装原始对象,将核心功能(如getColor())与装饰逻辑(如美白、换装)解耦。具体装饰器仅关注自身新增功能(MakeupDecorator专注美化肤色),代码可读性和维护性显著提升。

遵循开闭原则

新增装饰器(如添加“配饰装饰器”)无需修改现有代码,只需继承抽象装饰器即可。这种设计支持系统的渐进式扩展,降低耦合度,符合“对扩展开放,对修改关闭”的原则。

实践启示:

装饰器模式尤其适用于需动态、透明地扩展对象功能的场景。例如,Java I/O流中BufferedReader对FileReader的增强,或Web请求处理中的中间件链式调用。本文的男孩换装案例直观展现了装饰器的链式调用特性——每次装饰均基于前一步的结果,最终形成功能叠加或覆盖的效果(最后一次换装决定最终衣着)。

总之,装饰器模式如同为对象穿上“功能外衣”,让代码在保持简洁的同时,具备应对复杂需求的优雅扩展能力,是提升系统设计弹性的重要工具。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
    • 装饰器模式
    • 具体实例
      • 共有接口类
      • 具体被装饰类
      • 抽象装饰器类
      • 具体装饰器类
    • 测试
    • 装饰器模式的实际应用
      • Java I/O 体系
      • 游戏开发中的角色装备系统
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档