我目前正在开发一个涉及创建抽象层的项目.该项目的目标是在我可能需要切换到服务器软件时支持多种服务器软件实现.要抽象的功能列表相当长,所以我想要以一种相当轻松的方式来实现它.
其他应用程序将能够与我的项目进行交互,并进行最终归结为传递给我正在使用的服务器的调用.
这就是问题所在.我在这个领域没有多少经验,我真的不确定如何让它成为死亡的三明治.这是一个大概应该是什么样子的链(以及我想要完成的事情).
/*
Software that is dependent on mine
|
Public API layer (called by other software)
|
Abstraction between API and my own internal code (this is the issue)
|
Internal code (this gets replaced per-implementation, as in, each implementation needs its own layer of this, so it's a different package of entirely different classes for each implementation)
|
The software I'm actually using to write this (which is called by the internal code)
*/
抽象层(显然是中间的那个)是我努力拼凑起来的.
现在,我只是坚持一个愚蠢的方面.我怎么可能使抽象层不是一系列的东西
public void someMethod() {
if(Implementation.getCurrentImplementation() == Implementation.TYPE1) {
// whatever we need to do for this specific implementation
else {
throw new NotImplementedException();
}
}
(原谅伪代码;同样,对于每个抽象级别的类中的每个方法,想象相同的情况,但对于切换/案例,因为这可能比每个方法的if链更好).
这似乎非常基本,但我无法想出一个合理的解决方案来解决这个问题.如果我没有清楚地解释我的观点,请解释我需要详细说明的内容.也许我在想这整件事都错了?
解决方法:
为什么不使用控制反转?
您有一组抽象,您创建了几个实现,然后配置您的公共API以使用其中一个实现.
您的API受实现继承的接口集保护.您可以在以后添加新实现而无需修改API代码,甚至可以在运行时进行切换.
我不知道是否反转控制IS依赖注入,或者DI是Ioc的一种形式,但……只是你从组件中删除了依赖管理的责任.
在这里,你将拥有
> API层(客户端使用的接口)
>实现(无限)
>包装器(通过引入impl来完成IoC)
API层:
// my-api.jar
public interface MyAPI {
String doSomething();
}
public interface MyAPIFactory {
MyAPI getImplementationOfMyAPI();
}
实现:
// red-my-api.jar
public class RedMyAPI implements MyAPI {
public String doSomething() {
return "red";
}
}
// green-my-api.jar
public class GreenMyAPI implements MyAPI {
public String doSomething() {
return "green";
}
}
// black-my-api.jar
public class BlackMyAPI implements MyAPI {
public String doSomething() {
return "black";
}
}
一些包装器提供了一种配置正确实现的方法.在这里,您可以在工厂中隐藏您的开关盒,或从配置中加载impl.
// wrapper-my-api.jar
public class NotFunnyMyAPIFactory implements MyAPIFactory {
private Config config;
public MyAPI getImplementationOfMyAPI() {
if (config.implType == GREEN) {
return new GreenMyAPI();
} else if (config.implType == BLACK) {
return new BlackMyAPI();
} else if (config.implType == RED) {
return new RedMyAPI();
} else {
// throw...
}
}
}
public class ReflectionMyAPIFactory implements MyAPIFactory {
private Properties prop;
public MyAPI getImplementationOfMyAPI() {
return (MyAPI) Class.forName(prop.get('myApi.implementation.className'))
}
}
// other possible strategies
工厂允许使用几种策略来加载类.根据解决方案,您只需添加新的依赖项并更改配置(并重新加载应用程序……或不更改)以更改实施.
您可能也想测试表演.
如果使用Spring,则只能使用代码中的接口,并从配置类中注入正确的实现(Spring是DI容器).但是不需要使用Spring,您可以直接在Main入口点上执行此操作(从最近的入口点进行注入).
> my-api.jar没有依赖关系(或者可能是某些内部层).
>实现的所有jar都依赖于my-api.jar和你的内部代码.
>包装jar依赖于my-api.jar和一些impl jar.
所以客户端加载他想要的jar,使用他想要的工厂或注入impl的配置,并使用你的代码.这还取决于你如何暴露你的api.