【问题标题】:Idiom for container classes [closed]容器类的成语[关闭]
【发布时间】:2014-07-01 04:14:47
【问题描述】:

我被告知根据以下代码示例开发我的代码:

Class Dogs{
   List<Dog> listOfDogs = new ArrayList<Dog>();
   // Setters, getters...
}

Class Dog{
   // Attributes and methods
}

问题是:为什么将Dogs 类实现为Dog 对象的ArrayList 的容器而不是仅仅引用一个简单的ArrayList 更好。 这算不算封装?

【问题讨论】:

  • 这很大程度上取决于你想表达什么。在合同中,您可能希望有明确的类集合,而在普通程序中,您不需要这样。最后你真的应该问那个告诉你为什么他认为这样会更好的人。
  • 您可能会从这个问题的最佳答案中获得一些见解:stackoverflow.com/questions/21692193/why-not-inherit-from-listt 问题本身有点不同,但概念上有很多重叠

标签: java class containers idioms


【解决方案1】:

我认为没有理由创建一个单独的 Dogs 类,除非除了添加、删除和访问成员的标准集合操作之外,还有其他操作要对 Dogs 作为一个组执行。比如有releaseTheHounds()方法或者callEveryoneForDinner()方法等。

然而,您可能被告知应该使用List 类型来声明listOfDogs,而不是ArrayList。也就是这个:

List listOfDogs = new ArrayList<Dog>();

而不是这个:

ArrayList listOfDogs = new ArrayList<Dog>();

您已经这样做了,这是一个很好的做法。这里的“封装”是ArrayList作为List接口的实现者的隐藏。这使得很容易轻松切换到另一个实现(例如TreeList),而无需更改任何访问listOfDogs的代码。

最后但同样重要的是,你真的应该这样声明:

List<Dog> listOfDogs = new ArrayList<Dog>();

那么您要确保 List 包含 Dog 实例,而不是其他任何东西。

【讨论】:

  • 已编辑。我的问题是指将类用作简单容器,但感谢您的评论。我想说你的观点涉及多态性的概念,而不是封装;)
【解决方案2】:

当我们拥有一组对象的典型方法时,我们会使用这样的实现。因此,我们关注的不是特定的表示选择,而是共享的操作和属性。例如,stack 使用这种模式,通常在堆栈上可用的操作如下:push、remove、确定堆栈是否为空等。它使用 Object 代替 Dog;所以你可以堆叠任何对象。

现在您可以添加 Dog 以外的对象,它们将共享相同的方法。

【讨论】:

    【解决方案3】:

    基本上,创建Dogs 类为您提供了额外的间接层。

    这意味着您的所有其他代码将仅引用(即使用)Dogs 类,而不是内部列表。反过来,这意味着每当您决定从使用列表切换到例如在内部使用普通数组(或以任何其他方式更改 Dogs 的实现)时,您都可以轻松地这样做。

    这是它的动力。至于它是否“更好”的问题,很大程度上取决于您是否可以通过稳定的Dogs 的 API 来限制内部容器的使用。如果可以的话,创建一个Dogs 类是合理的。否则,直接使用List 会更简单、更容易。

    上述“稳定 API”的一个示例是访问者模式的应用。在这种情况下,Dogs 类应该有一个接受访问者参数的visit() 方法。访问者“知道”如何处理Dog,但完全不知道Dogs 的内部结构。这是一件好事。

    【讨论】:

    • 知道了。我看到了两个基本优势:隐藏实现细节(现在是 ArrayList,将来可能是 Set)和实现“自定义”方法(例如,检查 Dog 是否满足添加到列表中的要求的方法)。
    • 是的,这也是我的理解。顺便说一句,“自定义”方法的另一个有用类别是“批量”方法,它一次处理所有(或有意义的子集)项目。
    【解决方案4】:

    我明白为什么有人要求您这样做,尽管就像其他答案所暗示的那样,这个问题太宽泛而无法正确回答。视情况而定。

    现在这里的理由可能是,当您拥有 Dog 对象的容器时,您可以控制这些对象的创建、访问和更改方式。如果您只有一个列表,则无法真正控制对其的正确访问或添加/删除操作。但是,如果您有 Dogs 课程。您可以返回只读列表,不允许添加特定品种的狗等。它基本上可以作为所有与狗有关的控制器类。

    Class Dogs
    {
      List listofDogs = new ArrayList<Dog>();
    
      public void AddDog(Dog newDog)
      {
         //check if valid
      }
    
      public List<Dog> getDogs()
      {
        //return readonly dogs collection
      }
    }
    

    【讨论】:

    • 只读列表的返回对于并发很重要。我应该在自己的回答中提到这一点。 +1 给你!
    • 没错。对列表的更多控制。或者换句话说,您可以为此类对象集合改进或设置新的 API。
    【解决方案5】:

    这取决于您的问题以及您想要对该数组列表执行的操作。您可能想要扩展 ArrayList 的某些操作或添加将应用于所有数组列表项的新操作,例如排序方法此列表按 desc 顺序排列。

    【讨论】:

      【解决方案6】:

      我相信他们可能希望您从事类似于“对象池模式”的工作。对象池设计模式是一种创建设计模式,可以在处理实例化缓慢的类时提高性能。不是构造新对象,而是根据需要从池中检索和释放可重用对象。

      在这种情况下,Dogs 是 Pool,Dog 是 PooledObject,任何使用 PooledObject 类型对象的类都是客户端。

      【讨论】:

      • 为什么在这种情况下池需要是它自己的类,而不仅仅是一个ArrayList&lt;Dogs&gt;
      • 当池在其自己的类中时,您可以创建支持属性,例如保存对象首次创建的时间、锁定对象、清理并释放回池等跨度>
      • 对。我认为更一般的概念更多的是它所获得的 - 将数据和功能组合在一起的能力。您所描述的只是许多有用的情况中的一种
      【解决方案7】:

      使用我使用的 mvc 框架,它使网络表单的序列化变得更加容易

      【讨论】:

        猜你喜欢
        • 2010-09-23
        • 1970-01-01
        • 1970-01-01
        • 2018-12-30
        • 2011-05-07
        • 2010-09-14
        • 2022-06-15
        • 2011-01-25
        • 1970-01-01
        相关资源
        最近更新 更多