无法实现我的第一个装饰器模式
Having trouble implementing my first Decorator pattern
我有一个简单的应用程序,它接受一个字符串和 returns 字符串中唯一字符的数量。预计一个字符串可能会多次传递给该方法。该方法应该缓存结果,以便当给该方法一个以前遇到的字符串时,它会检索存储的结果。
出于学习目的,我需要使用装饰器模式实现缓存。我从网上学到的东西:
- 首先我创建一个界面
public interface CharCount {
Map<String, Long> charCount(String input);
}
- 实现简单 - 无需缓存
public class CharCountImplement {
Map<String, Long> charCount(String input) {
return Arrays.stream(input.split(""))
.collect(Collectors.groupingBy(Function.identity(), HashMap::new, Collectors.counting()));
}
}
- 装饰器class
public abstract class Decorator implements CharCount {
private CharCount charCount;
@Override
public Map<String, Long> charCount(String input) {
return charCount.charCount(input);
}
}
- 现在我必须创建具体的装饰器,但我不太明白
public class CachedDecorator extends Decorator {
// decorator must contain something else
public Map<String, Long> charCount(String input) {
// some decoration code - no problem with it
return super.charCount(input);
}
}
我不太明白这个设计模式的原理,以及如何在我的案例中使用它。
我有 watched/read 很多关于披萨和咖啡装饰器的教程,但没有帮助。
要使用缓存装饰 CharCount 对象,您可以使用如下内容:
public class CachedDecorator extends Decorator {
// NOTE: you don't realy need the abstract class Decorator
// you could also put the `private CharCount charCount;` into this class and let it implement CharCount instead of extending Decorator
// then you need to replace super.charCount(input) by charCount.charCount(input) in the charCount method in this class (the line is marked below)
private Map<String, Map<String, Long>> cache = new HashMap<>();
public CachedDecorator(CharCount charCount) {
this.charCount = charCount;//the base object that you are decorating
}
public Map<String, Long> charCount(String input) {
// --- start of the additional, decorating implementation
//check whether the input string was already processed and is cached
Map<String, Long> cached = cache.get(input);
if (cached != null) {
//we already know the solution, so just return it without calculating
return cached;
}
// --- call the super implementation that was decorated (where the super implementation in Decorator calls the charCount method of the CharCount object, that was added in the constructor of this class
Map<String, Long> calculated = super.charCount(input); //here you may also use charCount.charCount(input); instead of super.charCount(input); (see the NOTE in the top of this class)
// --- cache the result (again a decoration of the implementation)
cache.put(input, calculated);
// return the result
return calculated;
}
}
使用缓存的装饰器你可以做这样的事情:
CharCount simpleCharCount = new CharCountImplement();
CharCount cachingCharCount = new CachedDecorator(simpleCharCount);
simpleCharCount.charCount("Hello World!");// this will just calculate the result, because it's the simple object without cache
simpleCharCount.charCount("Hello World!");// the result is calculated another time
cachingCharCount.charCount("Hello World!");// this will use the simpleCharCount object to calculate the result map of "Hello World!" once
cachingCharCount.charCount("Hello World!");// this time the result is not calculated but just taken from the cache
装饰器模式相对于仅创建另一个实现的优势在于,您不必重新实现 CharCountImplement
class 中的代码,但您可以重复使用它。也可以在每个需要 CharCount
的地方使用 CacheDecorator
。因此,如果您有一个方法,需要一个 CharCount
对象作为参数并且正在使用 CharCountImplement
对象,您可以简单地使用 CacheDecorator
代替,而无需更改方法中的任何代码你正在打电话。
在这种情况下,您还可以创建一个扩展 CharCountImplement
的 class 来达到同样的效果。但是如果你想创建另一个 CharCount
接口的实现并且让这个新的实现也使用缓存,装饰器模式可以为你节省很多工作,因为你不需要创建这个缓存 subclass 用于 CharCount
的每个实现,但是您可以只为 CharCount
.
的每个实现使用一个装饰器
所以如果你有 4 个 CharCount
的实现,你可以使用 4 个 subclasses 来实现缓存,或者只使用 1 个装饰器。如果您想使用另一个装饰器,这种效果会呈指数级增长,因此这种模式可以真正帮助减少您需要创建的 classes 的数量并保持您的代码 DRY.
我有一个简单的应用程序,它接受一个字符串和 returns 字符串中唯一字符的数量。预计一个字符串可能会多次传递给该方法。该方法应该缓存结果,以便当给该方法一个以前遇到的字符串时,它会检索存储的结果。
出于学习目的,我需要使用装饰器模式实现缓存。我从网上学到的东西:
- 首先我创建一个界面
public interface CharCount {
Map<String, Long> charCount(String input);
}
- 实现简单 - 无需缓存
public class CharCountImplement {
Map<String, Long> charCount(String input) {
return Arrays.stream(input.split(""))
.collect(Collectors.groupingBy(Function.identity(), HashMap::new, Collectors.counting()));
}
}
- 装饰器class
public abstract class Decorator implements CharCount {
private CharCount charCount;
@Override
public Map<String, Long> charCount(String input) {
return charCount.charCount(input);
}
}
- 现在我必须创建具体的装饰器,但我不太明白
public class CachedDecorator extends Decorator {
// decorator must contain something else
public Map<String, Long> charCount(String input) {
// some decoration code - no problem with it
return super.charCount(input);
}
}
我不太明白这个设计模式的原理,以及如何在我的案例中使用它。 我有 watched/read 很多关于披萨和咖啡装饰器的教程,但没有帮助。
要使用缓存装饰 CharCount 对象,您可以使用如下内容:
public class CachedDecorator extends Decorator {
// NOTE: you don't realy need the abstract class Decorator
// you could also put the `private CharCount charCount;` into this class and let it implement CharCount instead of extending Decorator
// then you need to replace super.charCount(input) by charCount.charCount(input) in the charCount method in this class (the line is marked below)
private Map<String, Map<String, Long>> cache = new HashMap<>();
public CachedDecorator(CharCount charCount) {
this.charCount = charCount;//the base object that you are decorating
}
public Map<String, Long> charCount(String input) {
// --- start of the additional, decorating implementation
//check whether the input string was already processed and is cached
Map<String, Long> cached = cache.get(input);
if (cached != null) {
//we already know the solution, so just return it without calculating
return cached;
}
// --- call the super implementation that was decorated (where the super implementation in Decorator calls the charCount method of the CharCount object, that was added in the constructor of this class
Map<String, Long> calculated = super.charCount(input); //here you may also use charCount.charCount(input); instead of super.charCount(input); (see the NOTE in the top of this class)
// --- cache the result (again a decoration of the implementation)
cache.put(input, calculated);
// return the result
return calculated;
}
}
使用缓存的装饰器你可以做这样的事情:
CharCount simpleCharCount = new CharCountImplement();
CharCount cachingCharCount = new CachedDecorator(simpleCharCount);
simpleCharCount.charCount("Hello World!");// this will just calculate the result, because it's the simple object without cache
simpleCharCount.charCount("Hello World!");// the result is calculated another time
cachingCharCount.charCount("Hello World!");// this will use the simpleCharCount object to calculate the result map of "Hello World!" once
cachingCharCount.charCount("Hello World!");// this time the result is not calculated but just taken from the cache
装饰器模式相对于仅创建另一个实现的优势在于,您不必重新实现 CharCountImplement
class 中的代码,但您可以重复使用它。也可以在每个需要 CharCount
的地方使用 CacheDecorator
。因此,如果您有一个方法,需要一个 CharCount
对象作为参数并且正在使用 CharCountImplement
对象,您可以简单地使用 CacheDecorator
代替,而无需更改方法中的任何代码你正在打电话。
在这种情况下,您还可以创建一个扩展 CharCountImplement
的 class 来达到同样的效果。但是如果你想创建另一个 CharCount
接口的实现并且让这个新的实现也使用缓存,装饰器模式可以为你节省很多工作,因为你不需要创建这个缓存 subclass 用于 CharCount
的每个实现,但是您可以只为 CharCount
.
的每个实现使用一个装饰器
所以如果你有 4 个 CharCount
的实现,你可以使用 4 个 subclasses 来实现缓存,或者只使用 1 个装饰器。如果您想使用另一个装饰器,这种效果会呈指数级增长,因此这种模式可以真正帮助减少您需要创建的 classes 的数量并保持您的代码 DRY.