문제
이 중 어느 것이 사용하기에 가장 깨끗하거나 가장 좋은 것으로 간주되며 그 이유가 무엇인지 궁금합니다.
그 중 하나는 사용자가 승객을 추가하고 제거할 수 있는 승객 목록을 노출합니다.다른 하나는 목록을 숨기고 사용자가 목록을 열거하고 특별한 방법을 사용하여 추가하도록 합니다.
실시예 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);
내가 말하고 싶은 첫 번째 클래스는 더 잘 캡슐화되어 있습니다.그리고 이 정확한 경우에는 이것이 더 나은 접근 방식일 수 있습니다(버스 등에 공간이 남아 있는지 확인해야 하기 때문입니다).그런데 2학년도 유용하게 쓸 수 있는 경우가 있지 않을까요?마치 클래스가 목록이 있는 한 그 목록에 무슨 일이 일어나는지 전혀 신경 쓰지 않는 것처럼 말이죠.어떻게 생각하나요?
해결책
예를 들어, 컬렉션을 돌연변이 할 수 있습니다.
다음을 고려하세요:
var passengers = (List<Passenger>)bus.Passengers;
// Now I have control of the list!
passengers.Add(...);
passengers.Remove(...);
이 문제를 해결하려면 다음과 같은 것을 고려할 수 있습니다.
class Bus
{
private List<Passenger> passengers;
// Never expose the original collection
public IEnumerable<Passenger> Passengers
{
get { return passengers.Select(p => p); }
}
// Or expose the original collection as read only
public ReadOnlyCollection<Passenger> ReadOnlyPassengers
{
get { return passengers.AsReadOnly(); }
}
public void AddPassenger(Passenger passenger)
{
passengers.Add(passenger);
}
}
다른 팁
대부분의 경우 내부 클래스가 컬렉션에 대한 모든 변경 사항에 응답할 수 있도록 기본 유형이 확장 가능하고 onAdded/onRemoved 이벤트 형식을 노출하는 경우 예제 2를 허용할 수 있다고 생각합니다.
이 경우 List<T>는 클래스가 무언가 추가되었는지 알 수 있는 방법이 없기 때문에 적합하지 않습니다.대신 Collection<T> 클래스에는 재정의할 수 있고 래핑 클래스에 알리기 위해 이벤트 트리거를 추가할 수 있는 여러 가상 멤버(Insert,Remove,Set,Clear)가 있으므로 Collection을 사용해야 합니다.
(또한 클래스 사용자가 상위 클래스가 알지 못하는 사이에 목록/컬렉션의 항목을 수정할 수 있다는 점을 알아야 합니다. 따라서 항목이 변경되지 않을 것이라고 확신하지 마십시오. 명백히 변경할 수 없는 경우는 제외됩니다. - 또는 필요한 경우 onChanged 스타일 이벤트를 제공할 수 있습니다.)
FXCOP를 통해 각각의 예제를 실행하면 노출 위험에 대한 힌트를 줄 수 있습니다. List<T>
나는 그것이 당신의 상황에 달려 있다고 말할 것입니다. 나는 보통 옵션 2를 위해 가장 간단하기 때문에 갈 것입니다. ~하지 않는 한 당신은 그것에 더 큰 컨트롤을 추가 할 사업적인 이유가 있습니다.
옵션 2가 가장 간단하지만 다른 클래스가 컬렉션에 요소를 추가/제거 할 수있게 해주므로 위험 할 수 있습니다.
좋은 휴리스틱은 래퍼 방법이 무엇을하는지 고려하는 것입니다. AddPassenger (또는 제거 또는 기타) 메소드가 단순히 컬렉션에 호출을 전달하는 경우 더 간단한 버전으로 이동합니다. 요소를 확인 해야하는 경우 ~ 전에 그것들을 삽입하면 옵션 1은 기본적으로 피할 수 없습니다. 삽입/삭제 된 요소를 추적 해야하는 경우 어느 쪽이든 갈 수 있습니다. 옵션 2를 사용하면 알림을 얻으려면 컬렉션에 이벤트를 등록해야하며 옵션 1을 사용하면 사용하려는 목록의 모든 작업에 대한 랩퍼를 만들어야합니다 (예 : 삽입 및 추가를 원하는 경우). 때에 따라 다르지.