抽象层 (Java)
Abstraction Layer (Java)
我目前正在从事一个涉及创建抽象层的项目。该项目的目标是在我可能需要切换到它的情况下支持服务器软件的多种实现。要抽象的功能列表很长,所以我想研究一种相当轻松的方法。
其他应用程序将能够与我的项目交互并进行调用,最终将归结为传递到我正在使用的服务器。
问题就出在这里。我在这方面没有太多经验,我真的不确定如何让它不成为死亡三明治。这是它应该看起来的大致样子(以及我正在努力完成的事情)的链条。
/*
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();
}
}
(请原谅伪代码;另外,想象一下相同的情况,但对于 switch/case,因为对于每个抽象中的每个方法,这可能比每个方法的 if 链更好)-级别class。
这看起来很初级,但我想不出一个合乎逻辑的解决方案来解决这个问题。如果我没有清楚地解释我的观点,请解释我需要详细说明的内容。也许我对这整件事的思考是错误的?
为什么不使用控制反转?
您有一组抽象,创建了多个实现,然后配置 public api 以使用其中一个实现。
您的 API 受到实现继承的接口集的保护。您可以稍后添加新的实现而无需修改 API 代码,甚至可以在运行时切换。
我不知道控制反转是否是依赖注入,或者 DI 是否是 Ioc 的一种形式,但是...只是您从组件中删除了依赖管理的责任。
在这里,你将拥有
- API层(客户端使用的接口)
- 实现(无限)
- wrapper(通过引入 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";
}
}
一些包装器提供了一种配置正确实现的方法。在这里,您可以在工厂中隐藏开关盒,或从配置中加载实现。
// 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
工厂允许使用多种策略来加载class。根据解决方案,您只需添加新的依赖项并更改配置(并重新加载应用程序...或不重新加载应用程序)即可更改实现。
您可能还想测试性能。
如果使用Spring,则只能在代码中使用接口,并从配置class 中注入正确的实现(Spring 是DI 容器)。但是不需要使用 Spring,你可以直接在 Main 入口点上这样做(你从最近的入口点注入)。
- my-api.jar 没有依赖关系(或者可能对内部层有一些依赖关系)。
- 所有用于实现的 jar 都取决于我的-api.jar 和您的内部代码。
- wrapper jar 依赖于我的-api.jar 和一些 impl jar。
因此客户端加载他想要的 jar,使用他想要的工厂或注入 impl 的配置,并使用你的代码。这也取决于你如何暴露你的 api.
我目前正在从事一个涉及创建抽象层的项目。该项目的目标是在我可能需要切换到它的情况下支持服务器软件的多种实现。要抽象的功能列表很长,所以我想研究一种相当轻松的方法。
其他应用程序将能够与我的项目交互并进行调用,最终将归结为传递到我正在使用的服务器。
问题就出在这里。我在这方面没有太多经验,我真的不确定如何让它不成为死亡三明治。这是它应该看起来的大致样子(以及我正在努力完成的事情)的链条。
/*
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();
}
}
(请原谅伪代码;另外,想象一下相同的情况,但对于 switch/case,因为对于每个抽象中的每个方法,这可能比每个方法的 if 链更好)-级别class。
这看起来很初级,但我想不出一个合乎逻辑的解决方案来解决这个问题。如果我没有清楚地解释我的观点,请解释我需要详细说明的内容。也许我对这整件事的思考是错误的?
为什么不使用控制反转?
您有一组抽象,创建了多个实现,然后配置 public api 以使用其中一个实现。
您的 API 受到实现继承的接口集的保护。您可以稍后添加新的实现而无需修改 API 代码,甚至可以在运行时切换。
我不知道控制反转是否是依赖注入,或者 DI 是否是 Ioc 的一种形式,但是...只是您从组件中删除了依赖管理的责任。
在这里,你将拥有
- API层(客户端使用的接口)
- 实现(无限)
- wrapper(通过引入 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";
}
}
一些包装器提供了一种配置正确实现的方法。在这里,您可以在工厂中隐藏开关盒,或从配置中加载实现。
// 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
工厂允许使用多种策略来加载class。根据解决方案,您只需添加新的依赖项并更改配置(并重新加载应用程序...或不重新加载应用程序)即可更改实现。
您可能还想测试性能。
如果使用Spring,则只能在代码中使用接口,并从配置class 中注入正确的实现(Spring 是DI 容器)。但是不需要使用 Spring,你可以直接在 Main 入口点上这样做(你从最近的入口点注入)。
- my-api.jar 没有依赖关系(或者可能对内部层有一些依赖关系)。
- 所有用于实现的 jar 都取决于我的-api.jar 和您的内部代码。
- wrapper jar 依赖于我的-api.jar 和一些 impl jar。
因此客户端加载他想要的 jar,使用他想要的工厂或注入 impl 的配置,并使用你的代码。这也取决于你如何暴露你的 api.