Java接口-防止代码重复

问题描述 投票:0回答:2

我正在尝试为一组类创建接口,但我没有找到解决方案,防止为每个新方法复制几乎相似的代码界面。

界面

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 {
        ...
    }
}

容器类初始化所有实现,提供对它们每个的访问点。

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.");
        }
    }
}

测试班

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界面中重复管理每种方法的最佳解决方案是什么?

java interface wildcard repeat extends
2个回答
0
投票

您可以使用地图:

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。一旦进入该方法,如果该类不匹配,它将被强制转换并抛出RuntimeException,但是从编译器/接口方面,完全可以编写这样的代码。


0
投票

这似乎是经典的factorystrategy模式问题,其中违反了Open/Closed原则。您想扩展您的应用程序,但不修改它。

@@ kutschkem的解决方案是迄今为止最优雅的方法。另外,我建议在创建第一个业务对象时实例化策略/业务对象管理器。

这将使您无需再枚举BOM,因为建议的方法Open/Closed原则仍然受到侵犯。引入新的业务对象后,需要在类中添加其相应的管理器。

解决方案可能如下:

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的子程序包中。

© www.soinside.com 2019 - 2024. All rights reserved.