在 java 中使用 getter 方法向 List 添加元素是一种不好的做法吗?
Is it a bad practice to add elements to List using getter method in java?
假设我在 class 中有一个 private ArrayList
或一个 LinkedList
,我永远不会为它分配新的引用,或者换句话说,这永远不会发生:
myLinkedList = anotherLinkedList;
这样我就不需要使用 setMyLinkedList(anotherLinkedList)
。
但是!我需要向其中添加元素,或从中删除元素。
我应该写一种新的setter
来完成adding
的任务而不是像myLinkedList.add(someElement)
那样的setting
吗?
或者在不违背Encapsulation
原则的情况下使用getter
就可以了?
getMyLinkedList().add(someElement)
( + 假设我不遵守封装将失去我的标记:-")
一般来说,您不应假定 getter 返回的列表就是原始列表。例如,它可以被装饰或代理。
如果要防止在目标对象上设置新列表,可以改为在目标 class 上定义一个添加方法。
我建议在这种情况下最好遵循您的封装原则并使用一种方法将元素添加到列表中。您已通过将列表设置为 private
来限制对列表的访问,这样其他 classes 就无法直接访问该数据类型。
让存储您的 ArrayList
的 class 可以直接访问列表,但是当其他 class 想要添加到列表时,请使用 add()
方法。
我认为做这样的事情不是特别好的做法:
myObj.getMyList().add(x);
因为您以非只读方式公开私有 class 变量,但话虽如此,我确实经常看到它(我在看着您,自动生成 classes ).我会争辩说,不是那样做,return 一个不可修改的列表,并允许 class 的用户通过显式方法添加到列表中:
public class MyClass{
private final List<String> myList = new ArrayList<String>();
public List<String> getList(){
return Collections.unmodifiableList(this.myList);
}
public void addToList(final String s){
this.myList.add(s);
}
}
编辑 在查看了您的评论后,我想补充一点关于您的 setter 想法:
I meant using that line of code inside a new kind of setter inside the class itself, like public void setter(someElement){this.myLinkedList.add(someElement);}
如果我的理解正确,你是说你想要公开一个只会添加到你的列表中的方法。总的来说,这就是我认为你应该追求的目标,以及许多人在答案中概述的内容,但是,将其标记为 setter 有点误导,因为你没有重新分配(设置)任何东西。那,如果可能的话,我强烈建议 return 使用您的 getter 方法创建一个只读列表。
只要您拥有任何类型的 Collection
,将 add()
、remove()
之类的方法添加到 [=25] 的接口通常是个不错的主意=] 如果客户可以从您的私有列表中添加或删除对象是有意义的。
实现这些额外的方法很有用(这可能看起来有点矫枉过正,因为毕竟这些方法大多只是调用 Collection
上的方法)的原因是你可以保护恶意的客户不做你不希望他们做的事情,因为大多数 Collection
的接口包含的不仅仅是 add()
和 remove()
方法,而且大多数情况下,你不希望客户端去搞乱你无法控制的事情。所以封装原则对你老师来说很重要。
另一个加点:如果在任何时候,您会决定在将对象添加到列表时必须满足特定条件,这可以很容易地在您已有的方法中实现。如果你让客户端访问你的列表的直接引用,实现这种事情并不容易(这并不罕见)。
希望对您有所帮助
所以你有一个 class 包含一个 List
字段(它应该是 final
,因为你不打算分配给它),并且你想允许调用者添加到 List
,但无法替换它。
您可以为列表提供 getter:
public List<E> getMyList() {
return myList;
}
或提供添加到该列表的方法:
public void addToMyList(E e) {
myList.add(e);
}
两者都是有效的设计决策,但您使用哪个取决于您的用例。第一个选项让调用者直接访问 List
,有效地使其成为 public。这在用户将重复修改和使用列表时很有用,但可能会出现问题,因为您不再相信 List
处于任何可靠状态(调用者可以清空它,或重新排序,或者甚至恶意插入不同类型的对象)。因此,只有在您打算信任来电者时才应使用第一个选项。
第二个选项给了调用者更少的权力,因为他们一次只能添加一个元素。如果你想提供额外的功能(插入、添加等),你必须依次包装每个操作。但它让您更有信心,因为您可以确定 List
只会以您认可的方式进行修改。后一个选项还隐藏(封装)您正在使用 List
的实现细节,因此如果封装对您的用例很重要,您希望采用这种方式以避免暴露您的内部数据结构,并且仅公开您要授予调用者的行为。
这取决于应用程序 - 两者都可以接受。仔细查看您正在编写的 class 并决定是否要允许用户直接访问列表的内容,或者您是否希望他们先通过一些中间过程。
例如,假设您有一个 class ListEncrypter
,其中包含您的 MyLinkedList
列表。此 class 的目的是加密存储在 MyLinkedList
中的任何内容。在这种情况下,您需要提供一个自定义添加方法,以便在将添加的项目放入列表之前对其进行处理,如果您想要访问该元素,您还需要对其进行处理:
public void add(Object element)
{
MyLinkedList.add(encrypt(element););
}
public Object get(int index)
{
return decrypt(MyLinkedList.get(index););
}
在这种情况下,您显然想要拒绝用户访问 MyLinkedList
变量,因为内容将被加密并且他们无法对其进行任何操作。
另一方面,如果您并没有真正对数据进行任何处理(并且您确定将来永远不需要),您可以跳过创建专用方法,只允许用户通过 get
方法直接访问列表。
假设我在 class 中有一个 private ArrayList
或一个 LinkedList
,我永远不会为它分配新的引用,或者换句话说,这永远不会发生:
myLinkedList = anotherLinkedList;
这样我就不需要使用 setMyLinkedList(anotherLinkedList)
。
但是!我需要向其中添加元素,或从中删除元素。
我应该写一种新的
setter
来完成adding
的任务而不是像myLinkedList.add(someElement)
那样的setting
吗?或者在不违背
Encapsulation
原则的情况下使用getter
就可以了?getMyLinkedList().add(someElement)
( + 假设我不遵守封装将失去我的标记:-")
一般来说,您不应假定 getter 返回的列表就是原始列表。例如,它可以被装饰或代理。 如果要防止在目标对象上设置新列表,可以改为在目标 class 上定义一个添加方法。
我建议在这种情况下最好遵循您的封装原则并使用一种方法将元素添加到列表中。您已通过将列表设置为 private
来限制对列表的访问,这样其他 classes 就无法直接访问该数据类型。
让存储您的 ArrayList
的 class 可以直接访问列表,但是当其他 class 想要添加到列表时,请使用 add()
方法。
我认为做这样的事情不是特别好的做法:
myObj.getMyList().add(x);
因为您以非只读方式公开私有 class 变量,但话虽如此,我确实经常看到它(我在看着您,自动生成 classes ).我会争辩说,不是那样做,return 一个不可修改的列表,并允许 class 的用户通过显式方法添加到列表中:
public class MyClass{
private final List<String> myList = new ArrayList<String>();
public List<String> getList(){
return Collections.unmodifiableList(this.myList);
}
public void addToList(final String s){
this.myList.add(s);
}
}
编辑 在查看了您的评论后,我想补充一点关于您的 setter 想法:
I meant using that line of code inside a new kind of setter inside the class itself, like public void setter(someElement){this.myLinkedList.add(someElement);}
如果我的理解正确,你是说你想要公开一个只会添加到你的列表中的方法。总的来说,这就是我认为你应该追求的目标,以及许多人在答案中概述的内容,但是,将其标记为 setter 有点误导,因为你没有重新分配(设置)任何东西。那,如果可能的话,我强烈建议 return 使用您的 getter 方法创建一个只读列表。
只要您拥有任何类型的 Collection
,将 add()
、remove()
之类的方法添加到 [=25] 的接口通常是个不错的主意=] 如果客户可以从您的私有列表中添加或删除对象是有意义的。
实现这些额外的方法很有用(这可能看起来有点矫枉过正,因为毕竟这些方法大多只是调用 Collection
上的方法)的原因是你可以保护恶意的客户不做你不希望他们做的事情,因为大多数 Collection
的接口包含的不仅仅是 add()
和 remove()
方法,而且大多数情况下,你不希望客户端去搞乱你无法控制的事情。所以封装原则对你老师来说很重要。
另一个加点:如果在任何时候,您会决定在将对象添加到列表时必须满足特定条件,这可以很容易地在您已有的方法中实现。如果你让客户端访问你的列表的直接引用,实现这种事情并不容易(这并不罕见)。
希望对您有所帮助
所以你有一个 class 包含一个 List
字段(它应该是 final
,因为你不打算分配给它),并且你想允许调用者添加到 List
,但无法替换它。
您可以为列表提供 getter:
public List<E> getMyList() {
return myList;
}
或提供添加到该列表的方法:
public void addToMyList(E e) {
myList.add(e);
}
两者都是有效的设计决策,但您使用哪个取决于您的用例。第一个选项让调用者直接访问 List
,有效地使其成为 public。这在用户将重复修改和使用列表时很有用,但可能会出现问题,因为您不再相信 List
处于任何可靠状态(调用者可以清空它,或重新排序,或者甚至恶意插入不同类型的对象)。因此,只有在您打算信任来电者时才应使用第一个选项。
第二个选项给了调用者更少的权力,因为他们一次只能添加一个元素。如果你想提供额外的功能(插入、添加等),你必须依次包装每个操作。但它让您更有信心,因为您可以确定 List
只会以您认可的方式进行修改。后一个选项还隐藏(封装)您正在使用 List
的实现细节,因此如果封装对您的用例很重要,您希望采用这种方式以避免暴露您的内部数据结构,并且仅公开您要授予调用者的行为。
这取决于应用程序 - 两者都可以接受。仔细查看您正在编写的 class 并决定是否要允许用户直接访问列表的内容,或者您是否希望他们先通过一些中间过程。
例如,假设您有一个 class ListEncrypter
,其中包含您的 MyLinkedList
列表。此 class 的目的是加密存储在 MyLinkedList
中的任何内容。在这种情况下,您需要提供一个自定义添加方法,以便在将添加的项目放入列表之前对其进行处理,如果您想要访问该元素,您还需要对其进行处理:
public void add(Object element)
{
MyLinkedList.add(encrypt(element););
}
public Object get(int index)
{
return decrypt(MyLinkedList.get(index););
}
在这种情况下,您显然想要拒绝用户访问 MyLinkedList
变量,因为内容将被加密并且他们无法对其进行任何操作。
另一方面,如果您并没有真正对数据进行任何处理(并且您确定将来永远不需要),您可以跳过创建专用方法,只允许用户通过 get
方法直接访问列表。