装饰器模式是在这种情况下使用的正确模式吗
Posted
技术标签:
【中文标题】装饰器模式是在这种情况下使用的正确模式吗【英文标题】:Is the decorator pattern the correct pattern to be used on this situation 【发布时间】:2018-08-04 19:53:43 【问题描述】:我想问一下装饰器模式是否适合我的需求,是另一种让我的软件设计更好的方法吗?
以前我有一个始终开启的设备。在下面的代码中,这就是 Device 类。现在,为了节省一些电池寿命,我需要将其关闭然后再次打开。我创建了一个 DeviceWithOnOffDecorator 类。我使用了装饰器模式,我认为这有助于避免对 Device 类进行修改。但是每次操作都有On和Off,感觉代码不符合DRY原则。
namespace Decorator
interface IDevice
byte[] GetData();
void SendData();
class Device : IDevice
public byte[] GetData() return new byte[] 1,2,3 ;
public void SendData() Console.WriteLine("Sending Data");
// new requirement, the device needs to be turned on and turned off
// after each operation to save some Battery Power
class DeviceWithOnOffDecorator:IDevice
IDevice mIdevice;
public DeviceWithOnOffDecorator(IDevice d)
this.mIdevice = d;
Off();
void Off() Console.WriteLine("Off");
void On() Console.WriteLine("On");
public byte[] GetData()
On();
var b = mIdevice.GetData();
Off();
return b;
public void SendData()
On();
mIdevice.SendData();
Off();
class Program
static void Main(string[] args)
Device device = new Device();
DeviceWithOnOffDecorator devicewithOnOff = new DeviceWithOnOffDecorator(device);
IDevice iDevice = devicewithOnOff;
var data = iDevice.GetData();
iDevice.SendData();
在这个例子中:我只有 GetData 和 SendData 两个操作,但在实际的软件中涉及很多操作,我需要将每个操作都包含在内开和关,
void AnotherOperation1()
On();
// do all stuffs here
Off();
byte AnotherOperation2()
On();
byte b;
// do all stuffs here
Off();
return b;
我觉得每个函数都用 On 和 Off 括起来是重复的,有没有办法改进呢?
编辑:另外,原始代码是用 C++ 编写的。我只是在这里用 C# 写的,以便能够更清楚地显示问题。
【问题讨论】:
嗯。您正在寻找的是一种在您对On()
和Off()
的调用之间自动委托Device
类方法的方法。不幸的是,Java 不允许您动态添加方法,因此您无法“即时”构建修饰版本。如果您想深入了解虚拟机的内部,可以使用自定义类加载器来完成......但这不是一个实际的解决方案。相反,您可能想查看面向方面的编程。一个简短的搜索显示 android 对 AspectJ 有一些支持。从概念上讲,方面让您“挂钩”类的方法。
您好,感谢您的评论。但是,我忘了提一下,我是在 C++ 中实现的。在这种情况下,我只是使用了 C#,以便能够以更清晰的方式显示问题。
好吧,总是有 AspectC++,或者你可以解析 Device
类头并为修饰的子类生成代码(将调用从 Device
委托给 On()
和 Off()
之间的版本),或者您可以硬着头皮为Device
上的每个方法添加一个通用的“钩子”接口。然后您的 On/Off 子类可以安装用于打开和关闭电源的挂钩。至少 Device 中的钩子是通用的(不耦合到开/关功能)
【参考方案1】:
Decorator
不适合此目的,因为您没有动态添加责任。对我来说,您需要做的是拦截请求并在实际调用之前和之后执行on()
和off()
方法。为此,编写一个 Proxy
包装底层实例并在那里进行拦截,同时保持原始类型不变。
【讨论】:
以上是关于装饰器模式是在这种情况下使用的正确模式吗的主要内容,如果未能解决你的问题,请参考以下文章