OO设计封装

时间:2012-10-04 07:45:57

标签: oop encapsulation

我对封装有疑问。据我所知,封装允许使用私有/受保护数据成员隐藏实现细节,并提供操作数据的公共方法和属性。这里的想法是防止类消费者直接修改数据成员。

但我对属性getter或其他返回私有/受保护数据成员的公共方法感到担忧。例如:如果我有这样的课程

public class Inventory
{
    private List<Guitar> guitars = new List<Guitar>();

    public void AddGuitar(string serialnumber, string price)
    {
        Guitar guitar = new Guitar(serialnumber, price);
        guitars.Add(guitar);
    }

    public List<Guitar> GetGuitars()
    {
        return guitars;
    } 
}

现在,如果Inventory类消费者调用GetGuitars,他将获得在Inventory类中维护的吉他列表。现在,消费者可以修改列表,例如删除/添加/修改项目。对我来说,看起来我们没有封装。我想我应该在GetGuitars()中返回吉他列表项的副本。你怎么看?。

我对封装的理解是对吗?

由于

6 个答案:

答案 0 :(得分:1)

通过使用合适的接口限制对对象的访问,可以很好地实现封装对象列表。

我认为您可以通过AddGuitar方法控制对列表的添加,因为您可以控制进入的内容。您可以通过更改GetGuitars来返回IEnumerable而不是List来强化此设计,恕我直言。

这会减少调用者对列表的控制,同时也会在返回抽象类型时失去控制权。这样,您的内部数据结构可以在不需要公共接口的情况下进行更改。

答案 1 :(得分:1)

你是对的。使用类似的setter,客户端可以修改列表。如果添加吉他需要一些特殊处理,这是不希望的。在这种情况下,您有两种选择:

  1. 返回列表的副本(如您所建议的那样)。
  2. 在getter中用ReadOnlyCollection包裹它。
  3. 这两种情况都应记录在方法描述中,以便客户在尝试从外部修改列表时不会感到“惊讶”。

答案 2 :(得分:1)

如果你想要你的List数组无法修改,为什么你不使用AsReadOnly方法:http://msdn.microsoft.com/en-us/library/e78dcd75.aspx

关于成员内部封装的

只能通过外部无法获得成员的方法进行写入和读取。

答案 3 :(得分:1)

就风险而言,如果你返回一份无法修改的列表副本确实更好(当你添加吉他时,创建一个全新的不可修改的列表,函数编程风格)。

就封装而言,最好摆脱getGuitars()方法然后Inventory类应提供与之关联的功能(例如,printInventoryReport()或其他) 。这样,任何客户端类都不需要知道如何存储吉他,并将相关代码保存到Inventory类中。权衡是这个类变得更大,每当你需要吉他列表中的新东西时,你需要修改Inventory

我推荐一篇好文章:http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html 那天它非常煽动,但我认为那里有很多真相。

如果你坚持使用吸气剂,那么一个小小的提示就是选择你是List还是Collection能做到的。甚至可能是Iterable!通过这种方式,您可以尽可能少地了解实现,从而实现更好的封装。

答案 4 :(得分:0)

我同意返回列表会在封装方面留下一些需要的东西。您可能需要考虑为单个项目编写getter,或者可能考虑为迭代器编写getter。该列表看起来像一个实现细节,因此其他类实际上没有业务直接访问它。

答案 5 :(得分:0)

这里至少有两个问题。

第一个是关于隐藏实现。你可以改变吉他&#34;字段到数组或数据库但你可以保留方法AddGuitar和getGuitars的签名不变,所以客户端代码不会中断。

第二个是关于你是否想要返回吉他列表的防御性副本。一旦你有吉他列表,你想添加和删除元素吗?既然你有一种添加吉他的方法,我认为不会。