2017-06-10 86 views
1
class Product<T>{ 
    String name; 

    T category; 
} 

与下面的设计相比,哪一个更好,以及如何选择在不同的情况下?我觉得它们在功能上是相同的或非常相似的。泛型或继承/ Java中的接口?

class Product{ 
    String name; 
    Category category; 
} 

interface Category { 
    String type(); 
} 

class C1 implements Category{ 
    ... 
    @Override 
    String type(){ 
     ... 
    } 
} 

class C2 implements Category{ 
    ... 
    @Override 
    String type(){ 
     ... 
    } 
} 
+2

他们做不同的事情。通用版本指定了一个组件类型,对类型没有限制。继承版本指定了特定的类型。没有限制与特定类型是非常不同的。如果您不需要限制组件类型,请勿使用限制。在需要特定类型时使用特定类型。 –

+0

*“泛型或继承/ Java中的接口?”* ...是的。 – scottb

+1

您应该为第一个示例添加一个限制:'class Product '。使用该设计方法可以定义Compile-Time限制(“我只想要类别X的产品”):public void anyMethod(Product <?extends C2> product)'这可以很好地与 –

回答

1

有,你可以做到这一点第三种方式,我个人会选择:

interface Product 
{ 
    public String getName(); 
    public String getCategory(); 
} 

class Shirt implements Product 
{ 
    @Override 
    public String getName() 
    { 
     return "Shirt"; 
    } 

    @Override 
    public String getCategory() 
    { 
     return "Clothing"; 
    } 
} 

的原因,我建议这种方式是,你很可能将有不同类型的产品,例如衬衫,牛仔裤,内衣,一瓶牛奶。这些应该可能与Productis a的关系,即衬衫是产品,而一瓶牛奶是产品。这表明,Shirt会无论是从一些基本的继承Product类:

class Product 
{ 
    String name; 
    String category; 
} 

或者,将实施Product接口:

interface Product 
{ 
    public String getName(); 
    public String getCategory(); 
} 

这两种方法都可以工作,我喜欢的接口更多,因为它不”将你限制为单亲。现在,每一个产品能有更具体的属性,以及 - 例如,衬衫都会有大小,而一瓶牛奶会有一定量:

class MilkBottle implements Product 
{ 
    int volume; 

    @Override 
    public String getName() 
    { 
     return "Milk (" + volume + "ml)"; 
    } 

    @Override 
    public String getCategory() 
    { 
     return "Grocery"; 
    } 
} 

哪一个更好,如何选择哪种情况?

即使不是不可能,证明一种解决方案在编码方面比另一种更好。这是一个判断,你必须做出决定,而且你的经验会更好。话虽这么说,有两件事情你应该总是考虑:

  • 如何轻松将这个解决方案是使用?
  • 这个解决方案要保持多容易?

开始实施您的解决方案的小模型,并亲自看看您认为哪一个更好。实例化产品是否容易?或者单元测试这些类? 3个月后,当你决定添加一款新产品时呢?

我希望这可以帮助你在未来。

+0

这太好了。我花了数小时尝试使用泛型来解决我的问题后,终于找到了这样的解决方案。似乎泛型涉及更多的复杂性。 – user697911

1

重新阅读这个问题之后,我想我明白你问的更好一点 - 你如何决定是使通用成员还是使用接口?我会留下我的第一个答案,以防你觉得它有一些相关性,但这是一个更具体的答案。

假设我有一个'Order'类,它包含一个产品和要购买的数量。

class Order 
{ 
    Product product; 
    int quantity; 
} 

如果我改为使用Order类的泛型参数,会发生什么情况?

class GenericOrder<P> 
{ 
    P product; 
    int quantity; 
} 

正如@rollback在评论中指出的,product可能是任何东西!它可能是Shirt,或者它可能是int。关于P类型,我们唯一可以保证的是它继承自Object。我们需要添加一些约束条件,因此P必须是继承自(或实现)Product的某个类。

class GenericOrder<P extends Product> 
{ 
    P product; 
    int quantity; 
} 

现在,这两种解决方案就其实现而言几乎完全相同。 GenericOrder有点比普通的旧Order更灵活,因为你可以有这只需鞋订单的方法:

public int availableShoeBoxes(GenericOrder<Shoe> order) 
{ 
    ... 

你不能做到这一点与普通的旧Order,因此,如果您(或任何其他人使用你的代码)需要该用例,那么你应该使用泛型类型。

一个缺点的GenericOrder是,你必须要使用它的每一次指定P类型:

GenericOrder<Shirt> order = new GenericOrder<>(shirt, quantity); 

如果你并不需要能够做到在特定的操作顺序类型,为了简单起见,我建议使用Order类型。如果在未来某个时候,您发现自己需要通用版本的功能,在IDE中重构它并不困难。

+1

“......未来很难重构它”一旦发布了一个API,即客户端代码正在使用它,如果更改了代码使用的内容,就很难重构它。突然使类型通用会导致现有代码打破未经检查的警告。必须修改现有代码才能采用这些更改。在提交API之前要考虑周到。 –

+0

它可以像这样定义:class GenericOrder <?扩展产品> {}? – user697911

+0

@ user697911当你使用问号时,它基本上意味着'我不在乎这是什么类型,因为我不会直接引用它。这使得它在_declaration_类中毫无意义,因为你不能拥有特定类型的变量。当你使用这种类型时它更有用。在上面的最后一个例子中,'GenericOrder order'可以替换为'GenericOrder <?扩展产品>订单',以表明我不在乎销售什么类型的产品。 –