装饰器模式 logo

装饰器模式

Organization
microwind
装饰器模式

动态给对象添加职责。在需要为对象增加功能但又不想改变类本身时使用。

Overview

Publishermicrowind
Repositoryai-skills
Skill name装饰器模式
Stars
93
Forks
25
Bundled files
3
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 3 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by microwind on GitHub. Read the source before you install it.

Installation

Install the 装饰器模式 AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/microwind/ai-skills/tree/main/design-patterns/decorator-pattern
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/microwind/ai-skills.git /tmp/ai-skills
mkdir -p .claude/skills
cp -r /tmp/ai-skills/design-patterns/decorator-pattern .claude/skills/microwind-27
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable 装饰器模式 in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads 装饰器模式 on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so 装饰器模式 is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

装饰器模式 (Decorator Pattern)

概述

装饰器模式动态地给对象添加职责,不改变对象本身和外部接口。它提供了比继承更有弹性的替代方案来扩展功能。通过组合而不是继承,实现功能的灵活扩展。

核心原则:

  1. 组合优于继承: 使用组合而非继承来拓展功能
  2. 开闭原则: 对扩展开放,对修改关闭
  3. 单一职责: 每个装饰器只添加一个职责
  4. 透明性: 装饰器与被装饰对象有相同接口

与继承的根本区别:

继承方式:        装饰器方式:
Vehicle           ┌─ Vehicle (接口)
 ├─ Car              ├─ RealCar
 ├─ CarWithAC        ├─ ACDecorator
 ├─ CarWithSunroof      ├─ SunroofDecorator
 ├─ CarWithACAndSunroof ├─ CustomPaintDecorator
 └─ ...             └─ ...
 爆炸式增长          灵活组合

6个完美的使用场景

1. Java IO流处理(最经典应用)

文件读写需要支持多种功能组合:压缩、加密、缓冲、编码转换等。不能为每个组合创建子类。

java
// ❌ 不使用装饰器:类爆炸
FileInputStream
BufferedFileInputStream
GzipFileInputStream
GzipBufferedFileInputStream
GzipBufferedEncryptedFileInputStream
// ... 无法维护的组合爆炸

// ✅ 使用装饰器:灵活组合
InputStream in = new FileInputStream("file.txt.gz");
in = new GZIPInputStream(in);
in = new BufferedInputStream(in);
in = new CipherInputStream(in, cipher);
in = new InputStreamReader(in, "UTF-8");

2. Web框架中的功能中间件

服务方法需要支持多个功能:日志、缓存、鉴权、事务、性能监控、参数验证。每个功能独立,可选组合。

java
// HTTP请求处理链
UserService service = new UserServiceImpl();
service = new CachingDecorator(service);      // 添加缓存
service = new LoggingDecorator(service);      // 添加日志
service = new AuthenticationDecorator(service); // 添加鉴权
service = new ValidationDecorator(service);   // 添加验证
service = new TransactionDecorator(service);  // 添加事务

3. GUI组件功能扩展

窗口需要支持多种特效和行为的自由组合:边框、阴影、滚动条、透明度、缩放动画。

Window
 ├─ BorderWindow(添加边框)
 ├─ ShadowWindow(添加阴影)
 ├─ ScrollableWindow(添加滚动)
 └─ 可以组合任意组合

4. 数据处理管道

数据需要经过多个处理步骤的自由组合:验证、转换、加密、压缩、序列化。

java
DataProcessor processor = new RawDataProcessor();
processor = new ValidationDecorator(processor);
processor = new TransformationDecorator(processor);
processor = new EncryptionDecorator(processor);
processor = new CompressionDecorator(processor);

5. 咖啡订单系统(教科书例子)

基础咖啡可选添加配料:牛奶、糖、巧克力、肉桂等。价格和描述动态变化。

java
Coffee coffee = new SimpleCoffee();  // $2.0
coffee = new MilkDecorator(coffee);   // +$0.5 → $2.5
coffee = new SugarDecorator(coffee);  // +$0.3 → $2.8
coffee = new ChocolateDecorator(coffee); // +$0.7 → $3.5

6. 数据库连接池和连接包装

物理连接需要添加透明的功能:连接验证、性能监控、慢查询日志、自动重连。

java
Connection physicalConn = DriverManager.getConnection(url);
Connection conn = new MonitoringDecorator(physicalConn);
conn = new PooledConnectionDecorator(conn);
conn = new LoggingDecorator(conn);
conn = new TimeoutDecorator(conn);

4个实现方法对比

方法适用场景优点缺点选择指数
继承式装饰器规范工程类型安全代码多⭐⭐⭐⭐
泛型装饰器通用场景通用性强类型检查复杂⭐⭐⭐⭐⭐
函数式装饰器简单场景代码简洁难以复用⭐⭐⭐
动态代理AOP场景完全透明性能开销⭐⭐⭐

方法1: 继承式装饰器(标准实现)

java
// 基础接口
public interface DataStream {
    String read();
    void write(String data);
}

// 具体实现
public class FileDataStream implements DataStream {
    @Override
    public String read() {
        return "File data";
    }
    
    @Override
    public void write(String data) {
        System.out.println("Writing to file: " + data);
    }
}

// 抽象装饰器
public abstract class DataStreamDecorator implements DataStream {
    protected DataStream wrappedStream;
    
    protected DataStreamDecorator(DataStream stream) {
        this.wrappedStream = stream;
    }
}

// 具体装饰器1:压缩
public class CompressionDecorator extends DataStreamDecorator {
    public CompressionDecorator(DataStream stream) {
        super(stream);
    }
    
    @Override
    public String read() {
        String data = wrappedStream.read();
        return decompress(data);  // 解压
    }
    
    @Override
    public void write(String data) {
        String compressed = compress(data);
        wrappedStream.write(compressed);
    }
    
    private String compress(String data) { return "compressed(" + data + ")"; }
    private String decompress(String data) { return "decompressed(" + data + ")"; }
}

// 具体装饰器2:加密
public class EncryptionDecorator extends DataStreamDecorator {
    public EncryptionDecorator(DataStream stream) {
        super(stream);
    }
    
    @Override
    public String read() {
        String data = wrappedStream.read();
        return decrypt(data);
    }
    
    @Override
    public void write(String data) {
        String encrypted = encrypt(data);
        wrappedStream.write(encrypted);
    }
    
    private String encrypt(String data) { return "encrypted(" + data + ")"; }
    private String decrypt(String data) { return "decrypted(" + data + ")"; }
}

// 具体装饰器3:缓冲
public class BufferingDecorator extends DataStreamDecorator {
    private List<String> buffer = new ArrayList<>();
    private static final int BUFFER_SIZE = 1024;
    
    public BufferingDecorator(DataStream stream) {
        super(stream);
    }
    
    @Override
    public String read() {
        // 缓冲读取逻辑
        return wrappedStream.read();
    }
    
    @Override
    public void write(String data) {
        buffer.add(data);
        if (buffer.size() >= BUFFER_SIZE) {
            flush();
        }
    }
    
    public void flush() {
        buffer.forEach(wrappedStream::write);
        buffer.clear();
    }
}

// 使用示例
DataStream stream = new FileDataStream();
stream = new CompressionDecorator(stream);
stream = new EncryptionDecorator(stream);
stream = new BufferingDecorator(stream);

stream.write("Hello World");  // 自动压缩→加密→缓冲
String data = stream.read();  // 自动解缓冲→解密→解压

方法2: 泛型装饰器(通用性最强)

java
// 泛型装饰器,支持任何类型
public abstract class GenericDecorator<T> {
    protected T wrapped;
    
    protected GenericDecorator(T wrapped) {
        this.wrapped = wrapped;
    }
    
    // 子类可以灵活拦截任何方法
}

// 日志装饰器
public class LoggingDecorator<T> implements InvocationHandler {
    private T target;
    
    public LoggingDecorator(T target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        System.out.println("[LOG] Calling: " + method.getName());
        
        try {
            Object result = method.invoke(target, args);
            System.out.println("[LOG] Success: " + method.getName());
            return result;
        } catch (Exception e) {
            System.out.println("[LOG] Failed: " + method.getName());
            throw e;
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("[LOG] Duration: " + duration + "ms");
        }
    }
    
    @SuppressWarnings("unchecked")
    public <I> I decorate(Class<I> interfaceClass) {
        return (I) Proxy.newProxyInstance(
            interfaceClass.getClassLoader(),
            new Class[]{interfaceClass},
            this
        );
    }
}

// 使用示例(可装饰任何接口)
UserService originalService = new UserServiceImpl();
LoggingDecorator<UserService> decorator = new LoggingDecorator<>(originalService);
UserService loggingService = decorator.decorate(UserService.class);
loggingService.getUser(123);  // 自动记录日志

方法3: 函数式装饰器(Java 8+)

java
// 使用函数式接口
@FunctionalInterface
public interface Processor<T> {
    T process(T input);
}

// 装饰器工厂
public class FunctionalDecorators {
    // 日志装饰器
    public static <T> Processor<T> withLogging(Processor<T> processor) {
        return input -> {
            System.out.println("Processing: " + input);
            T result = processor.process(input);
            System.out.println("Result: " + result);
            return result;
        };
    }
    
    // 缓存装饰器
    public static <T> Processor<T> withCaching(Processor<T> processor) {
        Map<T, T> cache = new ConcurrentHashMap<>();
        return input -> cache.computeIfAbsent(input, k -> processor.process(k));
    }
    
    // 性能监控装饰器
    public static <T> Processor<T> withProfiling(Processor<T> processor) {
        return input -> {
            long start = System.currentTimeMillis();
            T result = processor.process(input);
            long duration = System.currentTimeMillis() - start;
            System.out.println("Execution time: " + duration + "ms");
            return result;
        };
    }
}

// 使用示例
Processor<Integer> processor = x -> x * 2;
processor = FunctionalDecorators.withLogging(processor);
processor = FunctionalDecorators.withCaching(processor);
processor = FunctionalDecorators.withProfiling(processor);

Integer result = processor.process(5);  // 链式调用所有装饰器

方法4: 动态代理装饰(AOP风格)

java
// 需要JDK动态代理或CGLIB
public class DecoratorProxy {
    public static <T> T decorate(T target, Class<T> interfaceClass, 
                                  List<Interceptor> interceptors) {
        return (T) Proxy.newProxyInstance(
            interfaceClass.getClassLoader(),
            new Class[]{interfaceClass},
            (proxy, method, args) -> {
                InterceptionChain chain = new InterceptionChain(method, target, interceptors);
                return chain.proceed(args);
            }
        );
    }
}

public interface Interceptor {
    Object intercept(Method method, Object[] args, InterceptionChain chain) throws Throwable;
}

// 使用示例
UserService service = new UserServiceImpl();
List<Interceptor> interceptors = Arrays.asList(
    new LoggingInterceptor(),
    new CachingInterceptor(),
    new PerformanceMonitorInterceptor()
);
UserService decoratedService = DecoratorProxy.decorate(service, UserService.class, interceptors);

4个常见问题 + 完整解决方案

问题1: 装饰器顺序问题 (Order Matters)

症状: 不同顺序的装饰导致结果完全不同,且很难发现

java
// ❌ 问题代码:顺序导致结果不一致
InputStream in1 = new FileInputStream("file.txt.gz");
in1 = new GZIPInputStream(in1);  // 先解压
in1 = new BufferedInputStream(in1);  // 再缓冲

// vs

InputStream in2 = new FileInputStream("file.txt.gz");
in2 = new BufferedInputStream(in2);  // 先缓冲
in2 = new GZIPInputStream(in2);  // 再解压
// in1和in2处理的数据不同!

// ✅ 解决方案1:记录装饰顺序
public class DecoratorChain<T> {
    private T target;
    private List<String> decorators = new ArrayList<>();
    
    public DecoratorChain(T target) {
        this.target = target;
    }
    
    public <D extends T> DecoratorChain<T> addDecorator(Class<D> decoratorClass) {
        decorators.add(decoratorClass.getSimpleName());
        return this;
    }
    
    public void printChain() {
        System.out.println("Decoration order: " + decorators);
    }
}

// ✅ 解决方案2:提供预定义的装饰器组合
public class DataStreamBuilder {
    private InputStream in;
    
    public DataStreamBuilder(InputStream in) {
        this.in = in;
    }
    
    public DataStreamBuilder withCompression() {
        try {
            in = new GZIPInputStream(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return this;
    }
    
    public DataStreamBuilder withBuffering() {
        in = new BufferedInputStream(in);
        return this;
    }
    
    public DataStreamBuilder withEncryption(Cipher cipher) {
        in = new CipherInputStream(in, cipher);
        return this;
    }
    
    // 正确的顺序:数据流→解压缩→解密→缓冲(解码)
    public InputStream buildForDecryption() {
        return withCompression()
            .withEncryption(null)  // 伪代码
            .withBuffering()
            .get();
    }
    
    public InputStream get() {
        return in;
    }
}

问题2: 装饰器与被装饰对象接口签名不匹配

症状: 装饰器添加了新方法,破坏了与原接口的一致性

java
// ❌ 问题代码:装饰器有额外方法
public class CachedUserService extends UserService {  // 继承而非实现接口
    @Override
    public User getUser(int id) {
        // 缓存逻辑
    }
    
    // 额外方法,破坏接口一致性
    public void clearCache() { }
    public Cache getCache() { }
}

// ✅ 解决方案:使用适配器模式或严格遵循接口
public interface UserService {
    User getUser(int id);
    // ... 其他方法
}

public class CachedUserServiceDecorator implements UserService {
    private UserService wrapped;
    private Cache cache;
    
    public CachedUserServiceDecorator(UserService wrapped, Cache cache) {
        this.wrapped = wrapped;
        this.cache = cache;
    }
    
    @Override
    public User getUser(int id) {
        User cached = cache.get(id);
        if (cached != null) return cached;
        
        User user = wrapped.getUser(id);
        cache.put(id, user);
        return user;
    }
    
    // 如需额外功能,提供独立方法
    public void clearCache() {
        if (cache instanceof Clearable) {
            ((Clearable) cache).clear();
        }
    }
}

问题3: 多层装饰导致性能问题和调试困难

症状: 8层装饰导致进程变得极其缓慢,且栈跟踪极深

java
// ❌ 问题代码:过度装饰
service = new LoggingDecorator(service);
service = new CachingDecorator(service);
service = new ValidationDecorator(service);
service = new TransactionDecorator(service);
service = new PerformanceMonitorDecorator(service);
service = new SecurityDecorator(service);
service = new AuditingDecorator(service);
service = new CircuitBreakerDecorator(service);  // 8层深度

// ✅ 解决方案1:限制装饰深度
public class DecoratorDepthValidator {
    private static final int MAX_DEPTH = 3;
    
    public static <T> void validate(T decorated) {
        int depth = calculateDepth(decorated);
        if (depth > MAX_DEPTH) {
            throw new IllegalArgumentException(
                "Decorator depth " + depth + " exceeds maximum " + MAX_DEPTH
            );
        }
    }
    
    private static <T> int calculateDepth(T obj) {
        int depth = 0;
        Object current = obj;
        while (current instanceof Decorator) {
            depth++;
            current = ((Decorator) current).getWrapped();
        }
        return depth;
    }
}

// ✅ 解决方案2:组合装饰器合并功能
public class ComprehensiveServiceDecorator implements UserService {
    private UserService wrapped;
    private Cache cache;
    private PerformanceMonitor monitor;
    private AuditLog auditLog;
    
    public ComprehensiveServiceDecorator(UserService wrapped) {
        this.wrapped = wrapped;
        this.cache = new Cache();
        this.monitor = new PerformanceMonitor();
        this.auditLog = new AuditLog();
    }
    
    @Override
    public User getUser(int id) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 缓存检查
            User cached = cache.get(id);
            if (cached != null) {
                auditLog.log("Cache hit for user " + id);
                return cached;
            }
            
            // 执行
            User user = wrapped.getUser(id);
            cache.put(id, user);
            
            // 审计
            auditLog.log("Fetched user " + id);
            return user;
            
        } finally {
            // 性能监控
            long duration = System.currentTimeMillis() - startTime;
            monitor.record("getUser", duration);
        }
    }
}

问题4: 装饰器链中异常处理不当

症状: 某个装饰器抛异常,导致整个链失败或失败模式不明确

java
// ❌ 问题代码:异常处理不当
public String process(String data) {
    data = compressionDecorator.process(data);  // 可能失败
    data = encryptionDecorator.process(data);    // 可能失败
    data = validationDecorator.process(data);    // 可能失败
    return data;  // 如果中间失败,状态不清
}

// ✅ 解决方案:完善的异常处理和恢复
public class ResilientDecoratorChain {
    private List<SafeDecorator> decorators = new ArrayList<>();
    private ErrorHandler errorHandler;
    
    public ResilientDecoratorChain(ErrorHandler errorHandler) {
        this.errorHandler = errorHandler;
    }
    
    public Result process(Input input) {
        Result current = new Result(input);
        
        for (int i = 0; i < decorators.size(); i++) {
            try {
                current = decorators.get(i).decorate(current);
            } catch (Exception e) {
                // 记录失败点
                errorHandler.handle(input, i, decorators.get(i), e);
                
                // 决定是否继续
                if (errorHandler.shouldContinue(e)) {
                    // 跳过此装饰器,继续下一个
                    continue;
                } else if (errorHandler.shouldRetry(e)) {
                    // 重试此装饰器
                    i--;
                    continue;
                } else {
                    // 中止处理,返回失败状态
                    return Result.failure(e);
                }
            }
        }
        
        return current;
    }
}

最佳实践指南

1️⃣ 装饰器职责要专一

java
// ❌ 一个装饰器做太多事
public class MegaDecorator extends DataStream {
    @Override
    public String read() {
        // 压缩、加密、日志、缓存、性能监控全部在这里
    }
}

// ✅ 各司其职
public class CompressionDecorator extends DataStream {
    @Override
    public String read() {
        return decompress(wrapped.read());
    }
}

public class LoggingDecorator extends DataStream {
    @Override
    public String read() {
        System.out.println("Reading...");
        return wrapped.read();
    }
}

2️⃣ 使用Builder模式简化装饰链构建

java
// ✅ Builder模式
public class DataStreamBuilder {
    private InputStream stream;
    
    public DataStreamBuilder(InputStream stream) {
        this.stream = stream;
    }
    
    public DataStreamBuilder compress() {
        stream = new CompressionDecorator(stream);
        return this;
    }
    
    public DataStreamBuilder encrypt(Cipher cipher) {
        stream = new EncryptionDecorator(stream, cipher);
        return this;
    }
    
    public DataStreamBuilder buffer() {
        stream = new BufferingDecorator(stream);
        return this;
    }
    
    public InputStream build() {
        return stream;
    }
}

// 使用
InputStream in = new DataStreamBuilder(
    new FileInputStream("data.bin")
)
    .compress()
    .encrypt(cipher)
    .buffer()
    .build();

3️⃣ 提供清晰的装饰器文档

java
/**
 * 缓存装饰器
 * 
 * 作用: 缓存方法调用结果
 * 
 * 使用场景:
 * - 方法调用结果稳定且获取开销大
 * - 可以接受短时间的数据延迟
 * 
 * 顺序建议:
 * - 应该在日志装饰器之后(避免记录缓存命中)
 * - 应该在数据转换装饰器之前(缓存转换后的结果)
 * 
 * 性能影响:
 * - 首次调用: +20% 开销(缓存存储)
 * - 缓存命中: -80% 开销(直接返回)
 * - 内存: +N * (key_size + value_size)
 * 
 * @param <T> 被装饰对象类型
 */
public class CachingDecorator<T> extends Decorator<T> {
    // 实现...
}

4️⃣ 支持装饰器的反思和诊断

java
public interface Decorator<T> {
    T getWrapped();
    String getDecoratorName();
    int getDecoratorDepth();
}

public class DecoratorDiagnostics {
    public static <T> void printChain(T decorated) {
        System.out.println("Decorator Chain:");
        Object current = decorated;
        int level = 0;
        
        while (current instanceof Decorator) {
            Decorator<?> decorator = (Decorator<?>) current;
            System.out.println(
                "  " + level + ". " + decorator.getDecoratorName()
            );
            current = decorator.getWrapped();
            level++;
        }
        
        System.out.println("  " + level + ". " + current.getClass().getSimpleName() + " (core)");
    }
}

5️⃣ 支持装饰器的动态移除和替换

java
public class RemovableDecorator<T> implements Decorator<T> {
    private T wrapped;
    private String name;
    
    public RemovableDecorator(T wrapped, String name) {
        this.wrapped = wrapped;
        this.name = name;
    }
    
    @Override
    public T getWrapped() {
        return wrapped;  // 支持剥离此装饰器
    }
    
    public T unwrap() {
        return wrapped;  // 移除自己,返回被包装的对象
    }
}

// 使用示例
UserService service = originalService;
service = new LoggingDecorator(service);
service = new CachingDecorator(service);
service = new ValidationDecorator(service);

// 如需移除缓存装饰
if (service instanceof RemovableDecorator) {
    RemovableDecorator<?> removable = (RemovableDecorator<?>) service;
    service = (UserService) removable.unwrap();  // 恢复到去掉缓存前的状态
}

与其他模式的关系

相关模式关系何时选择
Strategy都改变对象行为,但Strategy是替换算法,Decorator是添加功能需要替换→Strategy;需要扩展→Decorator
Proxy都包装对象,但Proxy通常是一对一,Decorator支持多层需要访问控制→Proxy;需要功能组合→Decorator
Adapter都改变接口,但Adapter改变不兼容接口,Decorator保持不变接口不匹配→Adapter;功能扩展→Decorator
Builder都实现灵活的对象构建,Decorator运行时动态,Builder是构造时静态构造时灵活→Builder;运行时灵活→Decorator
Composite都支持递归组合,但Composite处理树结构,Decorator是线性链树形结构→Composite;链式功能→Decorator

多语言实现考量

Java特性应用

  • 使用extends + implements支持多接口装饰
  • 利用@Delegate注解(Lombok)自动转发方法
  • Java IO是装饰器模式的标准库示范

Python考量

  • Python的鸭子类型使装饰器更灵活
  • 支持@property和属性转发
  • 函数装饰器(@decorator)比类装饰器更常见

TypeScript/JavaScript考量

  • 支持高阶函数,函数装饰器自然
  • 装饰器提案(@decorator)语言原生支持
  • 动态属性访问(Proxy对象)更强大

何时避免使用

  • ❌ 只需要简单继承: 类层级不复杂,功能组合不多
  • ❌ 性能极其关键: 多层装饰的调用链开销不可接受
  • ❌ 接口频繁变化: 装饰器维护成本超过继承
  • ❌ 装饰顺序复杂: 顺序依赖导致难以维护
  • ❌ 单个装饰器过于复杂: 应该考虑策略模式或责任链

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the 装饰器模式 AI skill do?

动态给对象添加职责。在需要为对象增加功能但又不想改变类本身时使用。

Why use 装饰器模式 on TypingMind?

Because you install it once and use it with any model. 装饰器模式 is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install 装饰器模式 in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/microwind/ai-skills/tree/main/design-patterns/decorator-pattern. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use 装饰器模式?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with 装饰器模式?

As many as you like. As long as a model supports skills, you can use 装饰器模式 with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the 装饰器模式 AI skill free?

Yes. It is published on GitHub by microwind under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇