C#:例如集合的封装
我想知道其中哪一个被认为是最干净或最好使用的以及为什么。
其中一个公开乘客列表,允许用户添加和删除等。另一个隐藏列表,只允许用户枚举它们并使用特殊方法添加。
示例 1
class Bus
{
public IEnumerable<Person> Passengers { get { return passengers; } }
private List<Passengers> passengers;
public Bus()
{
passengers = new List<Passenger>();
}
public void AddPassenger(Passenger passenger)
{
passengers.Add(passenger);
}
}
var bus = new Bus1();
bus.AddPassenger(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
示例 2
class Bus
{
public List<Person> Passengers { get; private set; }
public Bus()
{
Passengers = new List<Passenger>();
}
}
var bus = new Bus();
bus.Passengers.Add(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
我想说的第一个类封装得更好。 在这种情况下,这可能是更好的方法(因为您可能应该确保公交车上还有剩余空间等)。 但我想在某些情况下第二类也可能有用? 就像班级并不真正关心该列表会发生什么一样,只要它有一个列表即可。 你怎么认为?
I am wondering which one of these would be considered the cleanest or best to use and why.
One of them exposes the a list of passengers, which let the user add and remove etc. The other hides the list and only let the user enumerate them and add using a special method.
Example 1
class Bus
{
public IEnumerable<Person> Passengers { get { return passengers; } }
private List<Passengers> passengers;
public Bus()
{
passengers = new List<Passenger>();
}
public void AddPassenger(Passenger passenger)
{
passengers.Add(passenger);
}
}
var bus = new Bus1();
bus.AddPassenger(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
Example 2
class Bus
{
public List<Person> Passengers { get; private set; }
public Bus()
{
Passengers = new List<Passenger>();
}
}
var bus = new Bus();
bus.Passengers.Add(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
The first class I would say is better encapsulated. And in this exact case, that might be the better approach (since you should probably make sure it's space left on the bus, etc.). But I guess there might be cases where the second class may be useful as well? Like if the class doesn't really care what happens to that list as long as it has one. What do you think?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在示例一中,可以改变您的集合。
请考虑以下事项:
要解决此问题,您可以考虑如下:
In example one, it is possible to mutate your collection.
Consider the following:
To fix this, you might consider something like this:
在大多数情况下,我认为示例 2 是可以接受的,前提是基础类型是可扩展的和/或公开某种形式的 onAdded/onRemoved 事件,以便您的内部类可以响应对集合的任何更改。
在这种情况下,List不合适,因为类无法知道是否添加了某些内容。 相反,您应该使用 Collection,因为 Collection类有几个可以重写的虚拟成员(Insert、Remove、Set、Clear),并添加事件触发器来通知包装类。
(您还必须意识到该类的用户可以在父类不知情的情况下修改列表/集合中的项目,因此请确保您不依赖于未更改的项目 - 除非它们显然是不可变的- 或者如果需要,您可以提供 onChanged 样式事件。)
In most cases I would consider example 2 to be acceptable provided that the underlying type was extensible and/or exposed some form of onAdded/onRemoved events so that your internal class can respond to any changes to the collection.
In this case List<T> isn't suitable as there is no way for the class to know if something has been added. Instead you should use a Collection because the Collection<T> class has several virtual members (Insert,Remove,Set,Clear) that can be overridden and event triggers added to notify the wrapping class.
(You do also have to be aware that users of the class can modify the items in the list/collection without the parent class knowing about it, so make sure that you don't rely on the items being unchanged - unless they are immutable obviously - or you can provide onChanged style events if you need to.)
通过 FxCop 运行各自的示例,这应该会提示您暴露
List
的风险Run your respective examples through FxCop and that should give you a hint about the risks of exposing
List<T>
我想说这一切都取决于你的情况。 我通常会选择选项 2,因为它是最简单的,除非您出于业务原因需要对其添加更严格的控制。
I would say it all comes down to your situation. I would normally go for option 2 as it is the simplest, unless you have a business reason to add tighter controls to it.
选项 2 是最简单的,但它允许其他类向集合添加/删除元素,这可能很危险。
我认为一个好的启发是考虑包装方法的作用。 如果您的 AddPassenger (或 Remove 或其他)方法只是将调用中继到集合,那么我会选择更简单的版本。 如果您必须在插入元素之前检查它们,那么选项 1 基本上是不可避免的。 如果您必须跟踪插入/删除的元素,则可以采用任一方法。 使用选项 2,您必须在集合上注册事件才能获取通知,而使用选项 1,您必须为要使用的列表上的每个操作创建包装器(例如,如果您想要插入和添加),所以我猜这取决于。
Option 2 is the simplest, but that lets other classes to add/remove elements to the collection, which can be dangerous.
I think a good heuristic is to consider what the wrapper methods do. If your AddPassenger (or Remove, or others) method is simply relaying the call to the collection, then I would go for the simpler version. If you have to check the elements before inserting them, then option 1 is basically unavoidable. If you have to keep track of the elements inserted/deleted, you can go either way. With option 2 you have to register events on the collection to get notifications, and with option 1 you have to create wrappers for every operation on the list that you want to use (e.g. if you want Insert as well as Add), so I guess it depends.