2011-03-15 52 views
5

我正在做一个简单的程序,维护一个数字列表,我希望这个列表也有一个名字。最好的办法是让我的列表类扩展ArrayList或让它包含一个ArrayList成员?在这两种情况下,当然都会有一个“名称”字符串成员。我应该扩展ArrayList(is-a)还是应该将其作为成员(has-a)包含?

第一种方法意味着我只需要为该名称实现一个getter & setter,但是我认为这会将我的类与特定实现紧密联系在一起?例如,如果我想稍后使用Vector,则无需在任何地方更改代码。

第二种方法可以更容易地更改实现,但现在变得非常烦人,因为我必须实现一堆包装。

我读过关于继承与组合的SO帖子,由于我的列表是一种ArrayList,我倾向于第一种方法。然而,讨论有没有什么不同,因为我扩展了Collection类与扩展一般类?还是我过度思考这个?

回答

2

两者都不如您所说的更好,它是一种折衷。

如果你这样做聚合(已-a)您必须包装你要使用成员的所有功能(即实现调用它们的功能)

如果你继承,很多功能被添加到您可能不需要的新类中,而且您还需要实现抽象函数。

如果你是在C++环境下,私有继承将是一种选择,但在这里都有利弊

+0

一个解决方案需要更多的工作来实现并不意味着它不能在客观上比另一个更好。 – ColinD 2011-03-15 03:24:52

+0

你是对的,但这个解决方案不需要人工努力,可以通过工具实现自动化。因此没有考虑在traff off – AbiusX 2011-03-15 13:58:54

1

组成 - HAS-A。我更喜欢它为所有条纹的集合。

+0

你可以给出更喜欢成分的理由吗? – 2011-03-15 02:49:11

2

从长远来看,通常情况下最好包含成员而不是扩展。通过这种方式,您可以更加明确自己想要的内容,从而更容易测试并保持与课程的联系。如果你只是扩展ArrayList,那么它可能并不总是按照你的意图使用。当然,权衡是你必须为你想要允许的所有事情明确地创建传递方法。或者(或者另外),您可能想要提供一种方法来获取基础列表,您可以使用不可变集合来包装该列表,以保护它免受班级控制之外发生的变化的影响。

+0

我投了票,因为它与AbiusX相同,我接受了。我与我可以接受这两个:) – 2011-03-21 16:30:51

+0

谢谢。他确实回答了第一个问题:)但是,从我这里得到+1。 – WhiteFang34 2011-03-21 16:43:03

1

@AbiusX是对的。但第一种方法让我担心你的担心。请考虑下面,让我知道是这种方法有什么问题:

public class MyClass implements List 
{ 
    private String name; 
    private List myList = new ArrayList(); 

    public MyClass(String name) 
    { 
     this.name = name; 
    } 

    public String getName() 
    { 
     return name; 
    } 

    public void setName() 
    { 
     return name; 
    } 

    @Override 
    public void add(int index, Object element) 
    { 
     myList.add(index,element); 
    } 

    @Override 
    public boolean add(Object o) 
    { 
     myList.add(o); 
    } 

    @Override 
    public boolean addAll(Collection c) 
    { 
     myList.addAll(c); 
    } 

    //so on for rest of methods in List interface 
} 

我们还可以包括仿制药,如果你想让它键入数字安全。

0

继承ArrayList不是一个好主意,你需要一个强有力的理由来做到这一点。像Collections这样的工具类提供了几种不同风格的必要功能,所以您真的需要添加一些额外的必需功能来证明子类的正确性,就像一个非常知名的类。

3

为了两全其美,请使用GuavaForwardingList。这里有一个简单的例子:

public class NamedList<E> extends ForwardingList<E> implements RandomAccess { 
    // could also let the user provide the delegate list 
    private final List<E> delegate = Lists.newArrayList(); 
    private String name; 

    @Override protected List<E> delegate() { 
    return delegate; 
    } 

    // constructors, getter, setter 
} 

顺便说,延伸的具体收集实现,而不是使用成分的陷阱被discuseed在有效的Java项目16“青睐组成了继承权。”(在第2版)提到的几个问题之一与超类中方法之间相互作用的意外行为有关(例如,addaddAll)。

番石榴的Forwarding*类是在那里建议的解决方案的实现。

+0

谢谢,但我的问题更具理论性/哲学性 - 我想知道两种方法之间的优缺点。我不想寻找更复杂的解决方案。 – 2011-03-15 05:05:58

+1

@ red.october:我认为这是一个更简单的解决方案。在任何情况下,编写你自己的'ForwardingList'都很简单,并且是推荐的方法。 – ColinD 2011-03-15 06:14:35

+0

我不确定我是否同意 - 只是因为您利用现有代码而看起来更简单。 ForwardingList本质上是第二种方法 - 一类具有“传递”函数的类。 – 2011-03-15 06:28:39

相关问题