我第一次看到IO类中的装饰器模式。现在,我正在观看复数,封装和SOLID课程,其中课程讨论了装饰模式的另一种用法。这是类图。
MessageStore
|
<interface>
IStoreReader
|
---------------------------------------------------------
| | |
StoreLogger StoreCache FileStore
Message store是一个可以通过IStoreReader接口从任何文件或数据库读取的类。该类还有一种通过底层IStoreReader(FileStore)缓存数据返回的方法。最后,在通过StoreCache读取之前和之后记录MessageStore的整个操作。他应用了装饰器模式,因此初始化的类如下:
IStoreReader fileStore = new FileStore( some arguments);
IStoreReader cache = new FileStore(fileStore);
IStoreReader storeLogger = new StoreLogger(cache);
MessageStore messageStore = new MessageStore(storeLogger);
读取IStoreReader的唯一方法(int id)。
代码是这样的:
StoreLogger :
public List<String> read(int id){
log.information("Reading ...");
return this.storeReader.read(id);
log.information("Done reading ...");
}
StoreCache :
public List<String> read(id){
List<String> result = this.cache.find(id);
if(result.isEmpty()){
return this.storeReader.read(id);
}
return result;
}
FileStore:
public List<String> read(id){
//implementation
}
由于MessageStore只与一个IStoreReader进行交互,因此只传递了StoreLogger的实例,这就是那些困扰我的事情。如果将3个类传递给MessageStore(因为我认为这有点像服务类?)并且唯一的接口可以被3个更具体的接口替换,那么解决方案是否更好?可读性是此设计中的另一个问题。
另外,当我第一次看到如何使用装饰器模式时,我注意到它的目的是为传递的那个添加新值;如在IO中观察到的,如InputStream,BufferedInputStream等
请帮助我深入了解这一点。
答案 0 :(得分:1)
Decorator是一个非常强大的设计模式,因为它包装现有类并在其上添加更多功能,例如在您的情况下记录和缓存。并且接口的用户不需要知道正在使用哪个特定实现。
如果将3个类传递给,那么解决方案是不是更好 MessageStore(因为我相信这有点像服务类?)和 唯一的界面可以用3个更具体的界面代替吗?
不,因为如果你需要使用配置禁用缓存,你会怎么做? MessageStore
是否需要知道缓存已被禁用?如果提供给MessageStore
的对象不会缓存,那会更好。这就是多态性和装饰者的力量。
使用缓存:
IStoreReader reader = new StoreCache(new StoreLogger(new FileStore("file")));
没有缓存:
IStoreReader reader = new StoreLogger(new FileStore("file"));
因此,使用装饰器时发生的唯一变化是如何创建对象并将它们连接在一起。我认为这是一个更好的设计,因为只需要将一个对象传递给MessageStore
。
就日志记录而言,它也可以使用AOP完成,但它是开始使用装饰器的一个很好的例子。
如果您有任何疑问,请告诉我。
答案 1 :(得分:1)
装饰者模式的重点是将“动作”的动态组合链接在一起。对于您的示例,让我们看看它对您有何益处(与使用3个特定接口而不是1个更抽象的MessageStore
进行比较。
如果第一个存储失败,请考虑提供一些“备份”存储。然后,您可以使用以下StoreBackup
函数轻松创建IStoreRead
两个read
个实例:
public List<String> read(id){
List<String> result = this.mainStore.read(id);
if(result.isEmpty()){
result = this.backupStore.read(id);
}
return result;
}
另一个例子:假设你不想记录'cache hits',只记录真实的商店访问。然后您只需将构图顺序更改为
new StoreCache(new StoreLogger(new FileStore(...)))
当然,这也可以通过修改后的MessageStore
来完成,但需要您更改其代码(引入新的控制变量,方法等),而不仅仅是更改客户端代码。