假设我在课程中有private ArrayList
或LinkedList
,我永远不会为其分配新的引用,换句话说,这永远不会发生:
myLinkedList = anotherLinkedList;
因此我不需要使用setMyLinkedList(anotherLinkedList)
。
但是!我需要添加元素,或从中删除元素。
我应该只编写一种新的setter
,执行adding
而不是setting
的任务,例如myLinkedList.add(someElement)
吗?
或者可以使用getter
执行此操作,而不违反Encapsulation
委托人?
getMyLinkedList().add(someElement)
(+假设如果我不服从封装,我将失去我的标记: - “)
答案 0 :(得分:14)
我认为这样做不是特别好的做法:
public static JSpinner createJSpinnerAndAddToPanel(JPanel panel) {
JSpinner spinner = new JSpinner();
Dimension preferredSize = spinner.getPreferredSize();
preferredSize.width = 10;
spinner.setPreferredSize(preferredSize);
spinner.setAlignmentX(JSpinner.CENTER_ALIGNMENT);
panel.add(spinner);
return spinner;
}
因为您以非只读方式公开私有类变量,但据说我确实经常看到它(我正在看着你,自动生成的类)。我认为不是这样做,而是返回一个不可修改的列表,并允许该类用户通过显式方法添加到列表中:
myObj.getMyList().add(x);
编辑在审核了您的评论之后,我想补充一点关于您的设定理念:
我的意思是在类本身内部的一种新的setter中使用那行代码,比如public void setter(someElement){this.myLinkedList.add(someElement);}
如果我正确理解你,你说你想要公开一个只添加到你的列表中的方法。总的来说,这就是我认为你应该拍摄的内容,以及许多人在答案中概述的内容,然而,将其标记为制定者有点误导,因为你没有重新分配(设置)任何东西。那,我强烈建议如果可能的话,从你的getter方法中返回一个只读列表。
答案 1 :(得分:8)
通常,您不应该假设getter返回的列表是原始列表。例如,它可以被装饰或代理。 如果要防止在目标对象上设置新列表,则可以在目标类上定义add方法。
答案 2 :(得分:8)
我建议在这种情况下最好遵循您的Encapsulation主体并使用一种方法将元素添加到列表中。您可以通过将其private
限制访问列表,以便其他类无法直接访问数据类型。
让存储ArrayList
的类可以直接访问列表,但是当其他类要添加到列表中时,请使用add()
方法。
答案 3 :(得分:4)
只要您拥有Collection
任何类型,如果有意义的话,将add()
,remove()
等方法添加到班级的界面通常不是一个坏主意客户可以在私人列表中添加或删除对象。
为什么实现这些额外的方法是有用的(它可能看起来像是矫枉过正,因为所有这些方法大多只是调用Collection
上的方法)是因为你保护邪恶的客户端不做事情您不希望他们执行的列表,因为大多数Collection
的界面不仅包含add()
和remove()
方法,而且大多数情况下,您都不会希望客户能够搞乱你无法控制的事情。因此,封装原则对您的老师很重要。
另一个优点:如果在任何时候,当您将一个对象添加到列表中时,您将决定必须满足某个条件,这可以通过您已有的方法轻松实现。如果您让客户端访问您的列表的直接引用,那么实现这类事情并不容易(这种情况并不罕见)。
希望这有帮助
答案 4 :(得分:2)
如果我正确理解了您的问题,那么您有一个包含List
的类(它可能应该是final
,但您没有提及),并且您希望允许调用者添加到List
,但无法替换它。
你可以为列表提供一个getter:
public List<E> getMyList() {
return myList;
}
或提供添加到该列表的方法:
public void addToMyList(E e) {
myList.add(e);
}
两者都是有效的设计决策,但您使用的将取决于您的使用案例。第一个选项使呼叫者可以直接访问List
,从而有效地将其公开。当用户重复修改和使用列表时,这很有用,但可能会有问题,因为您无法再信任List
处于任何可靠状态(调用者可以清空它,或重新排序它,或者甚至恶意插入不同类型的对象)。因此,只有在您打算信任调用者时才应使用第一个选项。
第二个选项为调用者提供的功能更少,因为他们只能 一次添加一个元素。如果要提供其他功能(插入,添加所有等),您必须依次包装每个操作。但它会让您更有信心,因为您可以确定List
只是以您赞同的方式进行修改。后一个选项也隐藏(封装)您正在使用List
的实现细节,因此如果封装对您的用例很重要,您希望采用这种方式避免暴露您的内部数据结构,并且仅公开您要授予呼叫者的行为。
答案 5 :(得分:2)
这取决于应用程序 - 两者都是可以接受的。仔细查看您正在编写的类,并决定是否允许用户直接访问列表的内容,或者您是否希望首先通过某个中间过程。
例如,假设您有一个类ListEncrypter
,其中包含您的MyLinkedList
列表。此类的目的是加密MyLinkedList
中存储的任何内容。在这种情况下,您需要提供自定义添加方法,以便在将添加的项目放入列表之前处理添加的项目,如果您想访问该元素,您还需要处理它:
public void add(Object element)
{
MyLinkedList.add(encrypt(element););
}
public Object get(int index)
{
return decrypt(MyLinkedList.get(index););
}
在这种情况下,您显然想要拒绝用户访问MyLinkedList
变量,因为内容将被加密,并且无法对其执行任何操作。
另一方面,如果您没有真正对数据进行任何处理(并且您确定将来不再需要),则可以跳过创建专门的方法,只允许用户通过get
方法直接访问列表。