假设我有一个非常简单的界面来从某个地方获取文件:
interface FileManager {
File getFile(Object data);
}
我们可以假设此接口有多个实现,并且所有应用程序仅使用该接口,并且幸福地不知道OSGi上下文为其提供了哪些实现。
由于某些获取文件的方法非常慢,我想添加一个可选的缓存。但我不希望应用程序从FileManager
接口更改为另一个接口,因为这会让他们知道他们正在使用哪种实现(如果它很慢或没有)。
所以我想出了这个:
class FileManagerCache implements FileManager {
private final Map<Object, File> cache = new HashMap<>();
public File getFile(final Object data) {
if (this.cache.containsKey(data)) {
return this.cache.get(data);
}
final File result = getDelegate().getFile(data);
this.cache.put(data, result);
return result;
}
private FileManager getDelegate() {
for (final FileManager fileManager : ServiceUtil.findServices(FileManager.class)) {
if (this != fileManager) {
return fileManager;
}
}
throw new UnsupportedOperationException("No FileManager is present!"); //$NON-NLS-1$
}
}
此实现注册了一个非常高的"service.ranking"
,因此是应用程序使用的第一个实现,并且它会在可能的实现列表中委托给下一个实现。
现在这种方法不是很优雅,而且可能容易出错。如何使用标准机制在OSGi中创建代理?
答案 0 :(得分:1)
为另一个服务定义代理的更安全的方法是使用服务属性。 例如,您可以为慢速FileManager提供类似“name = A”的属性。
然后您可以为代理提供属性名称= A,cached = true。在初始化时,您可以为代理提供过滤器名称= A以搜索要代理的服务。
因此,如果需要缓存变体,服务的用户可以使用任何服务(按排名)或过滤cached = true。
答案 1 :(得分:0)
为什么不创建一个收集其他服务的注册实现的服务?样本实施以及您可以从here获得的想法。
答案 2 :(得分:0)
我认为你所描述的是一种2服务模式,因为你结合了多个职责。您将缓存责任与文件来源的抽象结合起来。或者换句话说,你的设计是混合问题,因此它不是 cohesive 。
因此,最简单的解决方案是拥有FileManager
和FileManagerProvider
服务。然后,您可以根据您的具体情况提供缓存的文件管理器和透明的文件管理器。
35年前,当我开始使用软件时,我得到了耦合,但我花了很多年才意识到凝聚力是多么重要。这个问题是一个非常典型的例子。
现在要了解为什么这种设计不好,您可以使用OSGi服务挂钩实现代理。您注册一个替代方案并隐藏原始服务。然而,由于所有代理相关的解决方案都有其自身的问题,因此制作技术劣质解决方案需要做很多工作。保持简单,直接,并使用实际类型来表示您的抽象是最好的解决方案。 (虽然我承认在我理解问题之前,我经常发现我最初制作了不粘合的设计。)
答案 3 :(得分:0)
Felix DependencyManager支持它。
的摘要依赖关系管理器 - 方面
Aspects,作为面向方面编程的一部分,可用于a 动态环境如OSGi“扩展”现有服务并添加 他们的某些“能力”。这些例子是添加a 特定的缓存机制到存储服务或实现 日志记录。 OSGi中的方面可以应用于服务并且可以添加 并在运行时删除。
方面允许您为服务定义“拦截器”或拦截器链,以添加缓存或日志记录等功能。一个方面将应用于与指定接口和过滤器匹配的任何服务。对于每个匹配服务,将基于方面实现类创建方面。该方面将使用与原始服务相同的界面和属性注册,以及您在此处提供的任何额外属性。它还将继承所有依赖项,如果您将原始服务声明为成员,则会注入它。
@AspectService(ranking=10), properties={@Property(name="param", value="value")})
class AspectService implements InterceptedService {
// The service we are intercepting (injected by reflection)
protected InterceptedService intercepted;
public void doWork() {
intercepted.doWork();
}
}