Java 接口 - 防止代码重复
Java interfaces - prevent code repetition
我正在尝试为一组 classes 创建一个界面,
但我没能找到解决方案
防止为每个新方法复制几乎相似的代码
界面。
界面
public interface P6BO<T extends BusinessObject> {
String[] getFields();
void create(T businessObject) throws P6BOException;
void delete(T businessObject) throws P6BOException;
}
30 多个接口实现。
public class ActivityBO implements P6BO<Activity> {
...
@Override
public void create(Activity activity) throws P6BOException {
...
}
@Override
public void delete(Activity activity) throws P6BOException {
...
}
}
容器class初始化所有的实现和
提供对每个人的单一访问点。
public class P6Bom {
public final ActivityBO activity = new ActivityBO();
public final EpsBO eps = new EpsBO();
public final ResourceBO resource = new ResourceBO();
public P6Bom(P6Info p6Info) throws P6BOException {
activity.activate(p6Info, p6Cache, p6Buffer);
eps.activate(p6Info, p6Cache, p6Buffer);
resource.activate(p6Info, p6Cache, p6Buffer);
}
...
public void create(BusinessObject businessObject) throws P6BOException {
if (businessObject instanceof Activity) {
activity.create((Activity) businessObject);
} else if (businessObject instanceof EPS) {
eps.create((EPS) businessObject);
} else if (businessObject instanceof Resource) {
resource.create((Resource) businessObject);
}
}
public void delete(BusinessObject businessObject) throws P6BOException {
if (businessObject instanceof Activity) {
activity.delete((Activity) businessObject);
} else if (businessObject instanceof EPS) {
eps.delete((EPS) businessObject);
} else if (businessObject instanceof Resource) {
resource.delete((Resource) businessObject);
}
}
public P6BO<? extends BusinessObject> getBO(BusinessObject businessObject) throws P6BOException {
if (businessObject instanceof Activity) {
return activity;
} else if (businessObject instanceof EPS) {
return eps;
} else if (businessObject instanceof Resource) {
return resource;
} else {
throw new P6BOException("not implemented.");
}
}
}
测试class
public class Test() {
/* Works: but is not generic (I cannot call the delete method for any BusinessObject). */
Activity activity = new Activity("MyNewActivity");
P6Bom.activity.create(activity);
P6Bom.activity.delete(activity);
/* Works: but results in a double administration in the P6Bom */
Activity activity = new Activity("MyNewActivity");
P6Bom.create(activity);
P6Bom.delete(activity);
/* Compiler error
The method delete(capture#1-of ? extends BusinessObject)
in the type P6BO<capture#1-of ? extends BusinessObject>
is not applicable for the arguments (Activity)
*/
p6Bom.getBO(activity).delete(activity);
}
什么是防止 P6Bom 界面中每个方法重复管理的优雅解决方案?
您可以使用地图:
public class P6Bom {
public final Map<Class<? extends P6BO<? extends BusinessObject>>, P6BO<? extends BusinessObject>>> classMap;
public P6Bom(P6Info p6Info) throws P6BOException {
classMap = new HashMap<>();
classMap.put(ActivityBo.class, new ActivityBO());
...
for(var bo: classMap.values()) {
bo.activate(p6Info, p6Cache, p6Buffer);
}
}
...
public void create(BusinessObject businessObject) throws P6BOException {
getBO(businessObject).create(businessObject);
}
public P6BO<? extends BusinessObject> getBO(BusinessObject businessObject) throws P6BOException {
if (classMap.containsKey(businessObject.getClass())) {
return classMap.get(businessObject.getClass());
} else {
throw new P6BOException("not implemented.");
}
}
}
我忘记了 <? extends BusinessObject>
是否允许您这样做。如果编译器抱怨,请在 classMap 声明和 getBO 签名中省略该部分并忽略警告 ;-)
这里要记住的是,在字节码中,泛型被删除,因此实际的方法签名允许您始终传入 BusinessObjects。一旦进入该方法,如果 class 不匹配,它将被强制转换并抛出 RuntimeException,但从 compiler/interface 方面来看,完全可以编写这样的代码。
这似乎是 class 典型的 factory
和 strategy
模式问题,其中违反了 Open/Closed
原则。您想扩展您的应用程序,但不对其进行修改。
@kutschkem 的解决方案是迄今为止最优雅的方法。此外,我建议在创建第一个业务对象时实例化 strategy/business 对象管理器。
这将使您免于枚举BOM
,因为建议的方式仍然违反了Open/Closed
原则。引入新的业务对象后,需要在 class.
中添加其各自的管理器
解决方案可能如下:
public class P6Bom {
private final Map<String, P6BO<? extends BusinessObject>> classMap;
private final P6Info info;
private final P6Cache cache;
private final P6Buffer buffer;
public P6Bom(P6Info info, P6Cache cache, P6Buffer buffer) {
this.classMap = new HashMap<>();
this.info = info;
this.cache = cache;
this.buffer = buffer;
}
public <T extends BusinessObject> void create(T businessObject) throws P6BOException {
this.getBO(businessObject).create(businessObject);
}
public <T extends BusinessObject> P6BO<T> getBO(T businessObject) throws P6BOException {
if (!this.classMap.containsKey(businessObject.getClass().getName())) {
try {
var bo = (P6BO<T>)Class.forName(businessObject.getClass().getPackageName() + ".bo." + businessObject.getClass().getSimpleName() + "BO").getConstructors()[0].newInstance();
bo.activate(this.info, this.cache, this.buffer)
this.classMap.put(
businessObject.getClass().getName(),
bo
);
} catch (Exception e) {
throw new P6BOException("not implemented.");
}
}
return (P6BO<T>)this.classMap.get(businessObject.getClass().getName());
}
}
当然,对于该解决方案,需要约定(或配置)如何为 BusinessObjects
找到策略(例如 ActivityBO)。在示例中,它们位于名为 bo
.
的子包中
我正在尝试为一组 classes 创建一个界面, 但我没能找到解决方案 防止为每个新方法复制几乎相似的代码 界面。
界面
public interface P6BO<T extends BusinessObject> {
String[] getFields();
void create(T businessObject) throws P6BOException;
void delete(T businessObject) throws P6BOException;
}
30 多个接口实现。
public class ActivityBO implements P6BO<Activity> {
...
@Override
public void create(Activity activity) throws P6BOException {
...
}
@Override
public void delete(Activity activity) throws P6BOException {
...
}
}
容器class初始化所有的实现和 提供对每个人的单一访问点。
public class P6Bom {
public final ActivityBO activity = new ActivityBO();
public final EpsBO eps = new EpsBO();
public final ResourceBO resource = new ResourceBO();
public P6Bom(P6Info p6Info) throws P6BOException {
activity.activate(p6Info, p6Cache, p6Buffer);
eps.activate(p6Info, p6Cache, p6Buffer);
resource.activate(p6Info, p6Cache, p6Buffer);
}
...
public void create(BusinessObject businessObject) throws P6BOException {
if (businessObject instanceof Activity) {
activity.create((Activity) businessObject);
} else if (businessObject instanceof EPS) {
eps.create((EPS) businessObject);
} else if (businessObject instanceof Resource) {
resource.create((Resource) businessObject);
}
}
public void delete(BusinessObject businessObject) throws P6BOException {
if (businessObject instanceof Activity) {
activity.delete((Activity) businessObject);
} else if (businessObject instanceof EPS) {
eps.delete((EPS) businessObject);
} else if (businessObject instanceof Resource) {
resource.delete((Resource) businessObject);
}
}
public P6BO<? extends BusinessObject> getBO(BusinessObject businessObject) throws P6BOException {
if (businessObject instanceof Activity) {
return activity;
} else if (businessObject instanceof EPS) {
return eps;
} else if (businessObject instanceof Resource) {
return resource;
} else {
throw new P6BOException("not implemented.");
}
}
}
测试class
public class Test() {
/* Works: but is not generic (I cannot call the delete method for any BusinessObject). */
Activity activity = new Activity("MyNewActivity");
P6Bom.activity.create(activity);
P6Bom.activity.delete(activity);
/* Works: but results in a double administration in the P6Bom */
Activity activity = new Activity("MyNewActivity");
P6Bom.create(activity);
P6Bom.delete(activity);
/* Compiler error
The method delete(capture#1-of ? extends BusinessObject)
in the type P6BO<capture#1-of ? extends BusinessObject>
is not applicable for the arguments (Activity)
*/
p6Bom.getBO(activity).delete(activity);
}
什么是防止 P6Bom 界面中每个方法重复管理的优雅解决方案?
您可以使用地图:
public class P6Bom {
public final Map<Class<? extends P6BO<? extends BusinessObject>>, P6BO<? extends BusinessObject>>> classMap;
public P6Bom(P6Info p6Info) throws P6BOException {
classMap = new HashMap<>();
classMap.put(ActivityBo.class, new ActivityBO());
...
for(var bo: classMap.values()) {
bo.activate(p6Info, p6Cache, p6Buffer);
}
}
...
public void create(BusinessObject businessObject) throws P6BOException {
getBO(businessObject).create(businessObject);
}
public P6BO<? extends BusinessObject> getBO(BusinessObject businessObject) throws P6BOException {
if (classMap.containsKey(businessObject.getClass())) {
return classMap.get(businessObject.getClass());
} else {
throw new P6BOException("not implemented.");
}
}
}
我忘记了 <? extends BusinessObject>
是否允许您这样做。如果编译器抱怨,请在 classMap 声明和 getBO 签名中省略该部分并忽略警告 ;-)
这里要记住的是,在字节码中,泛型被删除,因此实际的方法签名允许您始终传入 BusinessObjects。一旦进入该方法,如果 class 不匹配,它将被强制转换并抛出 RuntimeException,但从 compiler/interface 方面来看,完全可以编写这样的代码。
这似乎是 class 典型的 factory
和 strategy
模式问题,其中违反了 Open/Closed
原则。您想扩展您的应用程序,但不对其进行修改。
@kutschkem 的解决方案是迄今为止最优雅的方法。此外,我建议在创建第一个业务对象时实例化 strategy/business 对象管理器。
这将使您免于枚举BOM
,因为建议的方式仍然违反了Open/Closed
原则。引入新的业务对象后,需要在 class.
解决方案可能如下:
public class P6Bom {
private final Map<String, P6BO<? extends BusinessObject>> classMap;
private final P6Info info;
private final P6Cache cache;
private final P6Buffer buffer;
public P6Bom(P6Info info, P6Cache cache, P6Buffer buffer) {
this.classMap = new HashMap<>();
this.info = info;
this.cache = cache;
this.buffer = buffer;
}
public <T extends BusinessObject> void create(T businessObject) throws P6BOException {
this.getBO(businessObject).create(businessObject);
}
public <T extends BusinessObject> P6BO<T> getBO(T businessObject) throws P6BOException {
if (!this.classMap.containsKey(businessObject.getClass().getName())) {
try {
var bo = (P6BO<T>)Class.forName(businessObject.getClass().getPackageName() + ".bo." + businessObject.getClass().getSimpleName() + "BO").getConstructors()[0].newInstance();
bo.activate(this.info, this.cache, this.buffer)
this.classMap.put(
businessObject.getClass().getName(),
bo
);
} catch (Exception e) {
throw new P6BOException("not implemented.");
}
}
return (P6BO<T>)this.classMap.get(businessObject.getClass().getName());
}
}
当然,对于该解决方案,需要约定(或配置)如何为 BusinessObjects
找到策略(例如 ActivityBO)。在示例中,它们位于名为 bo
.