【问题标题】:Java generics for hiding type specific implementation?用于隐藏类型特定实现的 Java 泛型?
【发布时间】:2012-05-29 00:31:23
【问题描述】:

我正在尝试创建一个 API,以便在其他程序员使用我的服务时不需要实现和类名。该服务对“项目”执行各种操作,但服务应如何处理对项目的请求的主要影响因素是基于用户类型。到目前为止,我有一个接口 (Item) 和一个实现服务 (ItemService),然后是几个由此扩展的用户类型类(例如CompanyItemService)。用户类型也有一个结构,超类为User,子类如Company

public class ItemService<T extends User> extends Item {
    User user;
    public ItemService(User user) {
        this.user = user;
    }

    @Override
    public boolean belongsToUser() {
        //Check all records
    }
}

public class CompanyItemService<T extends Company> extends ItemService<Company> {
    public CompanyItemService(Company user) {
        super(user);
    }

    @Override
    public boolean belongsToUser() {
        //Check company specific records
    }
}

public class User {
    //Common user stuff
}

public class Company extends User {
    //Company specific stuff
}

所以我希望能够通过如下调用使用我的服务:

User company = new Company();
//stuff
Item item = new ItemService<Company>(company)
item.belongsToUser();

但是,当我这样做时,ItemService 中的方法被调用,而不是CompanyItemService 中的覆盖方法。是否有可能在不需要知道它属于 CompanyItemService 类的情况下获得这个覆盖方法?

干杯,

阿列克谢蓝。

所有这一切的总体思路是,当发明另一种用户类型时,可以根据需要添加另一种特定于用户的服务,而无需修改现有代码。此外,如果有很多用户类型,我只希望使用 API 的人必须记住使用 ItemService,然后让泛型来完成剩下的工作。

【问题讨论】:

    标签: java generics inheritance polymorphism


    【解决方案1】:

    您需要使用 abstract factory pattern. 简而言之,您需要一个知道所有可能的ItemService 子类的静态方法,并且给定一个Item 对象或Class它是User 的子类,返回正确的ItemService 子类的实例。换句话说,像

    public static ItemService<?> instance(Class<? extends User> c) {
        if (c == Customer.class)
            return new CustomerItemService();
        else if (c == Employee.class)
            return new EmployeeItemService();
        ...
    }
    

    那你可以说

    ItemService<?> service = ItemService.instance(Customer.class);
    

    或者,您可以构建地图:

    Map<Class<? extends User>, Class<? extends ItemService>> services = 
        new HashMap<Class<? extends User>, Class<? extends ItemService>>() {{
        put(Customer.class, CustomerItemService.class);
        put(Employee.class, EmployeeItemService.class);
        // more...
    }};
    

    那么instance() 可能看起来像

    ItemService<? extends User> instance(Class<? extends User> c) {
        return services.get(c);
    }
    

    【讨论】:

    • 我也应该有一个地图,类> :)
    • 感谢您的回答欧内斯特,所以假设我说大量的用户类型都有自己的实现,我猜我需要单独指定每一个?
    • @AlexeiBlue -- 正如@helios 所说,您可以使用Map 来保存有关类对的数据,因此代码本身将保持较小。可以在运行时获得very 的幻想并从属性文件中读取此类数据,或者提供registerItemService() 方法,让您在运行时通过代码安装其他数据。不过,如果只有几种类型,简单的if-then 就可以了。
    • 你能给我一个快速的例子,告诉我如何根据我的例子构建地图吗?泛型让我的眼睛变得模糊:S 谢谢
    【解决方案2】:

    代码可以正常工作。你创建一个 ItemService 的实例:

    Item item = new ItemService<Company>(company);
    

    如果您调用 ItemService 的 belongsToUser() 方法,将被调用。 您应该创建 CompanyItemService 的实例来调用它的方法。

    【讨论】:

    • 感谢您的回答 alexey28,但这就是我想要隐藏的。我对泛型的理解不是很好,但我猜这是它的众多用途之一。
    • 泛型只是帮助你不要手动转换 Float floatVal = (Float) objVal。而这一切。您不能在此处根据需要创建基于泛型类型的实例。您应该有一些注册表 - 具有键类和值的映射 - 应该创建的类的实例(对于单例)或通过反射调用的构造函数(例如原型)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-13
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    相关资源
    最近更新 更多