装饰器模式能否新增属性,还是仅能更新函数实现?
先纠正你对装饰器模式的核心误解
你观察到的「大部分装饰器示例都是给接口方法追加逻辑,没有真的给原对象动态加属性」是完全准确的——很多入门教程用“动态给对象加属性/特性”打比方是简化后的通俗说法,装饰器模式的准确定义是:在不修改原有类代码、不改变对象对外接口的前提下,给单个对象动态附加可叠加的额外职责。这些职责可以是纯行为逻辑,也完全可以携带独立的状态,只是这些状态是存在装饰器实例自身,不是硬塞到原对象的结构里。
用装饰器实现你需求的正确写法
你完全可以用装饰器解决现在不断给基类加字段的问题,核心思路是把每个额外的校验、追踪逻辑拆成独立的装饰器,每个装饰器自己存需要的状态,拦截对应属性的读写操作,不需要动原始业务对象的一行代码。
以C#实现为例,流程如下:
- 先定义所有业务对象统一实现的接口,原始业务类只保留最核心的业务字段,完全不掺杂任何校验、追踪逻辑
public interface IBusinessObject { int Value1 { get; set; } int Value2 { get; set; } } // 原始基础对象,只有核心业务字段 public class BaseBusinessObject : IBusinessObject { public int Value1 { get; set; } public int Value2 { get; set; } } - 实现装饰器基类,同样实现统一接口,内部持有一个被包装的业务对象实例,所有接口成员默认直接转发给内部对象
public abstract class BusinessObjectDecorator : IBusinessObject { protected readonly IBusinessObject _inner; protected BusinessObjectDecorator(IBusinessObject inner) { _inner = inner; } public virtual int Value1 { get => _inner.Value1; set => _inner.Value1 = value; } public virtual int Value2 { get => _inner.Value2; set => _inner.Value2 = value; } } - 把你要的「Value2跌破0事件追踪」拆成独立装饰器,自己存
EventHappened状态,拦截Value2的写入逻辑public class Value2BelowZeroTracker : BusinessObjectDecorator { // 额外状态存在装饰器自身,不需要修改原对象结构 public bool EventHappened { get; private set; } = false; public Value2BelowZeroTracker(IBusinessObject inner) : base(inner) { } public override int Value2 { get => _inner.Value2; set { _inner.Value2 = value; if (value < 0) { EventHappened = true; // 这里可以直接放事件触发时要执行的处理逻辑 } } } // 按需加重置方法 public void ResetTrackState() => EventHappened = false; } - 后续要加Value1的校验逻辑,不用改之前的任何代码,直接新增一个独立装饰器即可
public class Value1RangeValidator : BusinessObjectDecorator { private readonly int _minAllowedValue; public bool IsValue1OutOfRange { get; private set; } = false; public Value1RangeValidator(IBusinessObject inner, int minAllowedValue) : base(inner) { _minAllowedValue = minAllowedValue; } public override int Value1 { get => _inner.Value1; set { if (value < _minAllowedValue) { IsValue1OutOfRange = true; // 这里可以加告警、日志、抛错等任意逻辑 } _inner.Value1 = value; } } }
使用的时候可以按需自由叠加功能,不会出现基类膨胀:
// 初始化基础对象 IBusinessObject myObj = new BaseBusinessObject { Value1 = 1, Value2 = 2 }; // 叠加Value2跌破0追踪能力 myObj = new Value2BelowZeroTracker(myObj); // 再叠加Value1范围校验能力,要求Value1不能小于0 myObj = new Value1RangeValidator(myObj, minAllowedValue: 0);
你看到的那些图形、颜色相关的装饰器示例,之所以只修改Draw()方法,只是因为示例选的场景不需要存储额外状态而已,装饰器本身完全可以持有自己的属性和状态,没有任何规则限制它只能追加行为。
其他适配你场景的设计模式选择
装饰器不是唯一解,你可以根据自己的业务场景选更合适的方案:
- 如果你的校验、追踪逻辑是跨多类业务对象通用的,需要灵活插拔、自由组合功能,装饰器是最优选择,完全避免类爆炸和基类污染。
- 如果你只是需要给固定的一类对象加状态变更触发逻辑,用**观察者模式(事件驱动)**实现更轻量:给原始对象的属性加变更事件,所有追踪、校验逻辑写成独立的订阅者,状态存在订阅者侧,连包装层都不需要,耦合度更低。
- 如果你需要追踪的不只是单个布尔标记,而是一段时间内对象的所有状态变更历史,可以选备忘录模式,每次对象状态变更时存一个快照,后续任意时间点的状态、事件触发记录都可以从快照中查询。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

