Java设计模式详解--装饰器设计模式(含uml图)

一,初步理解

直接举个例子:

在这个例子中,结合以上图片与uml图进行分析不难得出:

Decorator装饰器

包含滚动条与边框,是它们的父类

滚动条与边框 都为ConcreteDecorator(具体装饰器)

Component

负责将装饰器与基础组件统计起来,说明每个组件与装饰器该完成什么统一的工作

比如这里,它们都需要画出来(draw())

所以显然,这里的文本框 并不属于装饰器,而是属于**(基础组件)**

二,看题目

Componet是界面组件中的抽象父类,其TextBox子类是文本框组件,Table子类是表格组件。

Decorator是抽象的装饰器父类,有两个具体的装饰器:ScrollDecorator给Componet画上滚动条

(简单地在被装饰对象draw()后System.out.print(" drawScroll")即可 )

BorderDecorator给Componet画上边框

(简单地在被装饰对象draw()后System.out.print(" drawBorder");即可 )

解题思路:

1.分析谁是ConcreteDecorator(具体装饰器) ,谁是ConcreteComponent(基础组件)

2.根据ConcreteDecorator(具体装饰器) 定义装饰器父类Decorator

3.根据ConcreteComponent(基础组件)Decorator统一组件行为(这里是draw())得到Component

于是画出类图:

代码附详细注释:

重点:

java 复制代码
class ScrollDecorator extends Decorator{
    private Component component;
    public ScrollDecorator(Component component){
        this.component=component;
    }
    public void draw(){
        component.draw();
        System.out.print(" drawScroll");
    }
}

class BorderDecorator extends Decorator{
    private Component component;
    public BorderDecorator(Component component){
        this.component=component;
    }
    public void draw(){
        component.draw();
        System.out.print(" drawBorder");
    }
}

对里面的一些代码进行说明:

装饰器的装饰:

1.对基础组件进行装饰

2.对被装饰过的组件进行继续装饰的行为(如装了滚动条还要装边框的情况)

所以有:先画出要装饰的组件情况,再加上自己装饰的内容

java 复制代码
    public void draw(){
        component.draw();
        System.out.print(" drawScroll");
    }

其他:

java 复制代码
/**
 * 抽象组件类(Component):装饰者模式的顶层抽象
 * 定义了所有具体组件(如TextBox、Table)和装饰者(Decorator)的统一接口
 * 核心作用是规范组件的绘制行为,为装饰者包装组件提供统一标准
 */
abstract class Component {
    /**
     * 抽象绘制方法:所有组件和装饰者都必须实现该方法,用于执行具体的绘制逻辑
     */
    abstract void draw();
}

/**
 * 具体组件类:文本框(TextBox)
 * 继承自抽象组件Component,实现了具体的绘制逻辑,是被装饰者包装的核心对象
 */
class TextBox extends Component {
    /**
     * 实现文本框的绘制逻辑
     * 输出文本框绘制的标识信息
     */
    @Override
    void draw() {
        System.out.print("drawTextBox");
    }
}

/**
 * 具体组件类:表格(Table)
 * 继承自抽象组件Component,实现了具体的表格绘制逻辑,是被装饰者包装的核心对象
 */
class Table extends Component {
    /**
     * 实现表格的绘制逻辑
     * 输出表格绘制的标识信息
     */
    @Override
    void draw() {
        System.out.print("drawTable");
    }
}

/**
 * 抽象装饰者类(Decorator):继承自Component,是所有具体装饰者的父类
 * 核心作用是持有组件对象(被装饰者),并统一装饰者的行为规范,实现对组件的功能扩展
 */
abstract class Decorator extends Component {
    // 持有抽象组件对象,用于包装(装饰)具体组件或其他装饰者(支持多层装饰)
    protected Component component;

    /**
     * 装饰者构造方法:传入需要被装饰的组件对象
     * @param component 被装饰的组件(可以是具体组件,也可以是其他装饰者对象)
     */
    public Decorator(Component component) {
        this.component = component;
    }
}

/**
 * 具体装饰者类:边框装饰者(BorderDecorator)
 * 继承自抽象装饰者Decorator,用于为组件添加"绘制边框"的额外功能
 */
class BorderDecorator extends Decorator {
    /**
     * 构造方法:传入需要添加边框装饰的组件
     * @param component 被装饰的组件(TextBox/Table或其他装饰者)
     */
    public BorderDecorator(Component component) {
        super(component); // 调用父类Decorator的构造方法,初始化被装饰组件
    }

    /**
     * 重写绘制方法:在原有组件绘制逻辑的基础上,添加边框绘制的功能
     * 这是装饰者模式的核心:不修改原有组件逻辑,通过包装扩展功能
     */
    @Override
    void draw() {
        // 1. 先执行额外的装饰逻辑:绘制边框(前置扩展)
        System.out.print("drawBorder->");
        // 2. 调用被装饰组件的draw方法,执行原有核心绘制逻辑
        component.draw();
    }
}

/**
 * 具体装饰者类:滚动条装饰者(ScrollDecorator)
 * 继承自抽象装饰者Decorator,用于为组件添加"绘制滚动条"的额外功能
 */
class ScrollDecorator extends Decorator {
    /**
     * 构造方法:传入需要添加滚动条装饰的组件
     * @param component 被装饰的组件(TextBox/Table或其他装饰者)
     */
    public ScrollDecorator(Component component) {
        super(component); // 调用父类Decorator的构造方法,初始化被装饰组件
    }

    /**
     * 重写绘制方法:在原有组件(或已装饰组件)绘制逻辑的基础上,添加滚动条绘制功能
     * 支持多层装饰嵌套(如先给Table加边框,再给带边框的Table加滚动条)
     */
    @Override
    void draw() {
        // 1. 先执行额外的装饰逻辑:绘制滚动条(前置扩展)
        System.out.print("drawScroll->");
        // 2. 调用被装饰组件的draw方法,执行其原有逻辑(可能是核心组件逻辑或其他装饰者逻辑)
        component.draw();
    }
}

/**
 * 主类:程序入口,用于测试装饰者模式的使用
 * 演示如何通过装饰者为具体组件添加多层额外功能
 */
public class Main{
    /**
     * 主方法:程序执行入口
     * @param args 命令行参数(本程序未使用)
     */
    public static void main(String[] args){
        // 1. 多层装饰:先给Table添加边框装饰,再给带边框的Table添加滚动条装饰
        // 最终得到一个"带滚动条+带边框"的Table组件
        Component table=new ScrollDecorator(new BorderDecorator(new Table()));
        
        // 2. 单层装饰:给TextBox添加边框装饰,得到一个"带边框"的TextBox组件
        Component text=new BorderDecorator(new TextBox());
        
        // 3. 调用装饰后的Table组件的绘制方法,会依次执行滚动条→边框→Table的绘制逻辑
        table.draw();
        
        // 换行:用于分隔两个组件的输出结果,提升可读性
        System.out.println();
        
        // 4. 调用装饰后的TextBox组件的绘制方法,会依次执行边框→TextBox的绘制逻辑
        text.draw();
    }
}

测试:

java 复制代码
/**
 * 主类:程序入口,用于测试装饰者模式的使用
 * 演示如何通过装饰者为具体组件添加多层额外功能
 */
public class Main{
    /**
     * 主方法:程序执行入口
     * @param args 命令行参数(本程序未使用)
     */
    public static void main(String[] args){
        // 1. 多层装饰:先给Table添加边框装饰,再给带边框的Table添加滚动条装饰
        // 最终得到一个"带滚动条+带边框"的Table组件
        Component table=new ScrollDecorator(new BorderDecorator(new Table()));
        
        // 2. 单层装饰:给TextBox添加边框装饰,得到一个"带边框"的TextBox组件
        Component text=new BorderDecorator(new TextBox());
        
        // 3. 调用装饰后的Table组件的绘制方法,会依次执行滚动条→边框→Table的绘制逻辑
        table.draw();
        
        // 换行:用于分隔两个组件的输出结果,提升可读性
        System.out.println();
        
        // 4. 调用装饰后的TextBox组件的绘制方法,会依次执行边框→TextBox的绘制逻辑
        text.draw();
    }
}

三,练习

Java IO 流的设计使用了装饰器设计模式,例如字符流输入流抽象类Reader 中有方法 public abstract int read() 读取一个字符 ; StringRead是具体的字符输入流,实现read()方法,从字符串中读取一个字符。FilterReader是抽象的装饰器类。请从FilterReader 类继承实现 LowerCaseStringReader ,把输入字符流中大写字母都转换为小写。

只需要 补充完成 LowerCaseStringReader 类,且仅需提交 LowerCaseStringReader 类即可

题目给出:

java 复制代码
class LowerCaseStringReader extends FilterReader {



    Reader in;



    protected LowerCaseStringReader(Reader in) {

        super(in);

        this.in=in;

    }



    @Override

    public  int read() throws IOException {

        /*

               请补充代码

         */

    }

}



public class Main{

    public static void main(String[] args) throws IOException {

        LowerCaseStringReader r=new LowerCaseStringReader(new StringReader("Design Pattern"));

        int c;

        while( (c=r.read())>0){

            System.out.print((char)c);

        }



    }

}
装饰器模式核心角色 本题对应的 Java IO 类 / 实现 角色说明
Component(抽象组件) Reader 抽象类 所有字符输入流(基础组件 + 装饰者)的顶层统一接口,定义了核心方法read()(读取一个字符),规范了所有字符输入流的行为标准
ConcreteComponent(具体基础组件) StringReader 继承自Reader,是被装饰的核心对象(无任何额外功能扩展,仅实现基础业务逻辑),负责从字符串中读取原始字符,不做任何转换处理
Decorator(抽象装饰者) FilterReader 1. 必须继承自抽象组件Reader(保证和基础组件具有统一接口,外部使用时无需区分 "基础组件" 和 "装饰者");2. 内部持有Reader类型的引用(可指向基础组件或其他装饰者,支持多层装饰);3. 本身是抽象类,不实现具体的扩展逻辑,仅作为所有具体装饰者的父类
ConcreteDecorator(具体装饰者) LowerCaseStringReader 类(本题需要实现的类) 1. 继承自抽象装饰者FilterReader;2. 持有被装饰的Reader对象(通过构造方法传入);3. 重写Reader的核心方法read(),在原有基础组件(StringReader)的read()方法基础上,添加 "大写字母转小写" 的扩展功能,这是装饰器模式的核心实现

需要的题目代码如下

java 复制代码
  public int read() throws IOException {
        // 1. 先调用被装饰对象(in,本质是StringReader)的read()方法,获取原始字符
        int originalChar = in.read();
        
        // 2. 判断字符是否有效(Reader的read()方法返回-1表示读取到流末尾)
        if (originalChar == -1) {
            return -1; // 到达流末尾,直接返回-1
        }
        
        // 3. 将原始字符转为char类型,判断是否为大写字母
        char ch = (char) originalChar;
        if (ch >= 'A' && ch <= 'Z') {
            // 大写字母转为小写:ASCII码中,大写字母+32对应小写字母
            return Character.toLowerCase(ch);
            // 等价于:return (char) (ch + 32);
        }
        
        // 4. 非大写字母,直接返回原始字符
        return originalChar;
    }

四,总结

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

设计模式系列持续更新,欢迎关注博主~

希望对大家有用,祝您开心~(o゜▽゜)o☆,有问题欢迎交流,俺会改的✊

相关推荐
杨充8 分钟前
10.可测试性实战设计
设计模式·开源·代码规范
杨充17 分钟前
9.重构十二式的实战
设计模式·开源·代码规范
糖果店的幽灵21 分钟前
langgraph的四种state解析
java·前端·javascript·langgraph
杨充27 分钟前
6.设计原则的全景图
设计模式·开源·全栈
杨充29 分钟前
4.接口而非实现编程
java·后端·架构
杨充29 分钟前
2.面向对象的特性
设计模式
杨充30 分钟前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充30 分钟前
8.反模式与坏味道
设计模式·开源·代码规范
梦梦代码精34 分钟前
基于ThinkPHP6 + Vue3的家政预约系统全解析:从LBS定位到自动派单的完整实现
java·docker·开源·php·代码规范
杨充39 分钟前
3.接口vs抽象类比较
设计模式