如何使类扩展另一个扩展类使用泛型集合?

时间:2016-08-25 11:25:48

标签: java generics inheritance

在我们当前的代码库中,我们有以下数据结构在服务层和前端层之间进行通信:

public class BaseView {
    private Integer id;
    // Other common attributes and getters/setters;
}

public class BarView extends BaseView {
    private String name;
    private String Description;
    // Other attributes for this object and getters/setters;
}

我们还有一些双扩展类:

public class BazView extends BaseView {
    // name, description, other common attributes;
}

public class BazTypeAView extends BazView {
    // attributes specific to Type A Baz;
}

public class BazTypeBView extends BazView {
    // attributes specific to Type B Baz;
}

在我们的服务层中,我们有实现BaseService的服务方法:BarServiceBazServiceBazTypeAServiceBazTypeBService以及具有类似命名方案的其他方法所有方法都返回他们负责的类,或者List<class they are responsible for>。反过来,这些方法中的每一个都从BaseService调用一个带有签名GetObjects(Class Viewtype, Class BeanType, Criteria)的方法,其中的条件基于传递给特定方法方法的参数。 Bean位于服务层和数据访问层之间,与此无关。

该计划的一个例子:

public interface BaseService {
    public BaseView getObject(Class viewType, class beanType, Integer id);

    public List<BaseView> getObjects(Class viewType, class beanType, Criteria criteria);
}

public class BaseServiceImpl implements BaseService {
    protected BaseView getObject(Class viewType, class beanType, Integer id){
        BaseBean bean = (BaseBean) DataService.getobject (beanType, id);
        BaseView view = ViewGenerator.createEmptyView(viewType);
        copyAttributes(bean, view);
        return view;
    }

    protected List<BaseView> getObject(Class viewType, class beanType, Criteria criteria){
        List<BaseBean> bean = (List<BaseBean>) DataService.getobject (beanType, Criteria);
        List<BaseView> view = new ArrayList<BaseView>();
        copyAttributes(bean, view);
        return view;
    }
}

public interface BarService extends BaseService {
    public BarView getBar(Integer id);

    public List<BarView> getBars(BarView barView);
}

public class BarServiceImpl extends BaseServiceImpl implements BarService {
    public BarView getBar(Integer id){
       BarView bar = getObject(BarView.class, BarBean.class, id);
       return bar;
    }

    public List<BarView> getBars(BarView barView){
       Criteria criteria = getCriteriaFromBarView(barView);
       List<BarView> bars = getObjects(BarView.class, BarBean.class, criteria);
       return bars;
    }
}

以上大致是系统的工作原理。创建条形图,获取条形图列表,更新条形图和删除条形图的方法都与上述方法有效。

问题是getObject返回一个原始List,导致很多Eclipse警告和代码难以阅读。我们对这个项目的警告超过2/3是关于原始类型的使用,虽然我们的代码仍然编译并按预期工作,但它有很多消息。

如果我们没有扩展扩展类的第二种View,我们可以只做List<? extends Fooview>,但这会给扩展BazView的类带来错误。有两种方法可以让泛型类型在这里工作吗?扩展Baseview和? extends X扩展了Baseview?

3 个答案:

答案 0 :(得分:2)

除了我猜你的BaseService是一个界面外,我的答案与其他答案没什么不同:

  

在我们的服务层,我们有服务方法实施一个BaseService

我会定义这样的界面(编辑):

public interface BaseService<T extends FooView>{
    T getObject(Class<T> viewType, Class<? extends FooBean> beanType, Integer id);    
    List<T> getAllObjects(Class<T> viewType, Class<? extends FooBean> beanType);
}

(的 ADDED ) 在抽象类中实现该接口要求所有依赖服务也使用泛型:

public abstract class BaseServiceImpl<T extends FooView> implements BaseService<T>{
    @Override
    public T getObject(Class<T> viewType, Class<? extends FooBean> beanType, Integer id){
        FooBean bean = DataService.getObject(beanType, id);
        T view = ViewGenerator.createEmptyView(viewType);
        copyAttributes(bean, view);

        return view;
    }

    @Override
    public List<T> getAllObjects(Class<T> viewType, Class<? extends FooBean> beanType){
        List<? extends FooBean> beanList = DataService.getAllObjects(beanType);

        return beanList.stream().map(bean -> {
            T view = ViewGenerator.createEmptyView(viewType);
            copyAttributes(bean, view);
            return view;
        }).collect(Collectors.toList());
    }

    private void copyAttributes(FooBean bean, T view){}
}

修改) 所有服务的实施应该是直截了当的:

public class BarServiceImpl extends BaseServiceImpl<BarView> implements BarService{

    @Override
    public BarView getBar(Integer id){
        return getObject(BarView.class, BarBean.class, id);
    }

    @Override
    public List<BarView> getAllBars(){
        return getAllObjects(BarView.class, BarBean.class);
    }
}

public class BazServiceImpl extends BaseServiceImpl<BazView> implements BazService{
    @Override
    public BazView getBaz(Integer id){
        return getObject(BazView.class, BazBean.class, id);
    }

    @Override
    public List<BazView> getAllBazs(){
        return getAllObjects(BazView.class, BazBean.class);
    }
}

public class BazTypeAServiceImpl extends BaseServiceImpl<BazTypeAView> implements BazTypeAService{
    @Override
    public BazTypeAView getBazTypeA(Integer id){
        return getObject(BazTypeAView.class, BazTypeABean.class, id);
    }

    @Override
    public List<BazTypeAView> getAllBazTypeAs(){
        return getAllObjects(BazTypeAView.class, BazTypeABean.class);
    }
}

至少在我的主要方法中没有警告,因为所有内容都是干净的类型:

public class Main{
    public static void main(String[] args){
        BarService barService = new BarServiceImpl();
        BarView barView = barService.getBar(111);
        List<BarView> barViewList = barService.getAllBars();

        BazService bazService = new BazServiceImpl();
        BazView bazView = bazService.getBaz(222);
        List<BazView> bazViewList = bazService.getAllBazs();

        BazTypeAService bazTypeAService = new BazTypeAServiceImpl();
        BazTypeAView bazTypeAView = bazTypeAService.getBazTypeA(333);
        List<BazTypeAView> bazTypeAViewList bazTypeAService.getAllBazTypeAs();
    }
}

注意:

使用抽象类替换接口(如果可能)将再次减少代码,因为两个示例方法都可以在抽象类中实现。主要方法根本不需要改变。

修改

您还需要在创建对象的级别使用泛型。否则你需要大量的投射,并且你的列表会收到那些丑陋的警告。我为你更新了样品。

<强> EDIT2

我之前已经提到过 DataService ViewGenerator 也需要使用泛型。这就是我实现方法体的方法:

public class DataService    {
    public static <T extends FooBean> T getObject(Class<T> beanType, Integer id){return null;}    
    public static <T extends FooBean> List<T> getAllObjects(Class<T> beanType){return null;}
}

public class ViewGenerator    {
    public static <T> T createEmptyView(Class<T> viewType){return null;}
}

答案 1 :(得分:0)

如果我理解正确,您需要的是让BaseService获得将在getObject方法中使用的通用类型:

BaseService类:

public class <T extends FooView> BaseService<T> {
  public T getObject() { 
   ...
  }
}

并在具体服务中:

public class BazTypeAService extends BaseService<BazTypeAView> {
  ...
}

答案 2 :(得分:0)

使用代码样式的快速答案,如果我不理解,我会删除它。

尝试使用这样的通用类型:

public abstract class BarService<T extends FooView>{
    List<T> list;
    ...

    public List<T> getList(){ return list;}
}

public class BazService extends BarService<BazView>{
    ...
}

public class BazTypeBService extends BarService<BazTypeBView>{
    ...
}

...

在这里,

BazService.getList() will return a List<BazView> instance
BazTypeBService .getList() will return a List<BazTypeBView> instance