设计图案装饰

时间:2015-03-08 05:59:52

标签: design-patterns decorator

我第一次看到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等

请帮助我深入了解这一点。

2 个答案:

答案 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来完成,但需要您更改其代码(引入新的控制变量,方法等),而不仅仅是更改客户端代码。

相关问题