다른 클래스의 ClassCollection을 만드는 것이 좋은 방법입니까?


35

Car수업 이 있다고 말합니다 .

public class Car
{
    public string Engine { get; set; }
    public string Seat { get; set; }
    public string Tires { get; set; }
}

우리는 주차장에 대한 시스템을 만들고 있다고 말하고 많은 Car수업 을 사용할 것이므로 수업을 만들면 다음 CarCollection과 같은 몇 가지 추가 방법이있을 수 있습니다 FindCarByModel.

public class CarCollection
{
    public List<Car> Cars { get; set; }

    public Car FindCarByModel(string model)
    {
        // code here
        return new Car();
    }
}

수업 ParkingLot을하는 경우 모범 사례는 무엇입니까?

옵션 1:

public class ParkingLot
{
    public List<Car> Cars { get; set; }
    //some other properties
}

옵션 # 2 :

public class ParkingLot
{
    public CarCollection Cars { get; set; }
    //some other properties
}

ClassCollection다른 것을 만드는 것이 좋은 습관 Class입니까?


주변 CarCollection이 아닌 다른 List<Car>곳 을 통과 할 때 어떤 이점이 있다고 생각 하십니까? 특히 CarCollection이 지원 목록 클래스를 확장하지 않거나 심지어 Collection 인터페이스를 구현하지 않는다는 점을 감안할 때 (C #이 비슷한 것을 확신합니다).

List <T>는 이미 IList <T>, ICollection <T>, IList, ICollection, IReadOnlyList <T>, IReadOnlyCollection <T>, IEnumerable <T> 및 IEnumerable ...을 구현하고 있습니다. 게다가 Linq를 사용할 수 있습니다 ...
Luis

그러나 public class CarCollectionIList 또는 ICollection 등을 구현하지 않으므로 목록에 문제가없는 것으로 전달할 수 없습니다. 이름의 일부로 컬렉션이라고 주장하지만 이러한 방법을 구현하지는 않습니다.

1
나는 6 살짜리 질문이므로 아무도 이것이 DDD에서 일반적인 관행이라고 언급하지 않았습니다. 모든 컬렉션은 사용자 지정 컬렉션으로 추상화해야합니다. 예를 들어 자동차 그룹의 가치를 계산하려고한다고 가정합니다. 그 논리를 어디에 두겠습니까? 서비스 중? 또는 DDD CarColection에서는 TotalTradeValue속성이 있습니다. DDD는 시스템을 설계하는 유일한 방법이 아니라 옵션으로 만 지적합니다.
스톰 뮬러

1
정확히, 이것들은 실제로 DDD에서 제안 된 것처럼 전체 뿌리입니다. DDD만이 자동차 컬렉션이라고 부르지 않는 것이 좋습니다. 오히려 주차장 또는 작업장 등과 같은 일부 이름을 사용하십시오.
코드 이름 Jack

답변:


40

.NET의 제네릭 이전에는 '유형'컬렉션을 만드는 것이 일반적 이었으므로 class CarCollection그룹화하는 데 필요한 모든 유형에 대해 etc를 갖습니다 . Generics가 도입 된 .NET 2.0에는 새로운 클래스 List<T>가 도입되어 생성 CarCollection할 수있는 등의 작성을 줄여줍니다 List<Car>.

대부분의 경우 List<T>자신의 목적에 충분하다는 것을 알 수 있지만 컬렉션에 특정 행동을 취하고 싶을 수도 있습니다.

  • List<T>예를 들어 캡슐화하는 클래스를 만듭니다.public class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
  • 맞춤 컬렉션 만들기 public class CarCollection : CollectionBase<Car> {}

캡슐화 방식을 사용하는 경우 열거자를 최소한 노출시켜야 다음과 같이 선언 할 수 있습니다.

public class CarCollection : IEnumerable<Car>
{
    private List<Car> cars = new List<Car>();

    public IEnumerator<Car> GetEnumerator() { return this.cars.GetEnumerator(); }
}

그렇게하지 않으면 foreach컬렉션을 넘을 수 없습니다 .

사용자 지정 컬렉션을 만들려는 몇 가지 이유는 다음과 같습니다.

  • IList<T>또는 모든 방법을 완전히 노출하고 싶지는 않습니다.ICollection<T>
  • 컬렉션에서 항목을 추가하거나 제거 할 때 추가 작업을 수행하려고합니다

좋은 습관입니까? 예를 들어 위에 나열된 이유 중 하나 인 경우, 당신이 그것을하고 있는지에 달려 있습니다.

Microsoft는 꽤 정기적으로 수행합니다. 여기에는 최근의 몇 가지 예가 있습니다.

당신의 FindBy방법에 관해서는 , 나는 그것들을 자동차가 포함 된 모든 컬렉션에 사용할 수 있도록 확장 방법에 넣고 싶습니다.

public static class CarLookupQueries
{
    public static Car FindByLicencePlate(this IEnumerable<Car> source, string licencePlate)
    {
        return source.SingleOrDefault(c => c.LicencePlate == licencePlate);
    }

    ...
}

이것은 자동차를 저장하는 클래스와 컬렉션을 쿼리하는 것에 대한 관심을 분리시킵니다.


이 접근법에 따라, 나는이 모든 방법을 캡슐화 ClassCollection할 새로운 CarCRUD것을 추가함으로써, 추가, 삭제, 업데이트 방법에 대한 짝수도 무시할 수 있다.
Luis

@Luis CarCRUD확장 기능을 사용하는 것이 어려울 수 있으므로 확장을 권장하지 않습니다 . 컬렉션 클래스에 사용자 정의 crud 논리를 배치하면 우회 할 수있는 방법이 없다는 장점이 있습니다. 또한 실제로 Caretc 등이 선언 된 핵심 어셈블리의 찾기 논리에 대해서는 신경 쓰지 않을 수 있습니다. 이는 UI 전용 활동 일 수 있습니다.
Trevor Pilley

MSDN의 메모와 마찬가지로 "새 개발에 CollectionBase 클래스를 사용하지 않는 것이 좋습니다. 대신 일반 Collection <T> 클래스를 사용하는 것이 좋습니다." - docs.microsoft.com/en-us/dotnet/api/...
라이언

9

아니요. XXXCollection클래스 생성은 .NET 2.0의 제네릭이 등장하면서 스타일에서 벗어났습니다. 실제로 Cast<T>()요즘 사람들이 이러한 사용자 정의 형식에서 물건을 얻는 데 사용 하는 멋진 LINQ 확장이 있습니다.


1
우리가 그 안에 가질 수있는 사용자 정의 방법은 ClassCollection어떻습니까? 메인에 배치하는 것이 좋은 습관 Class입니까?
Luis

3
나는 그것이 "의존적"이라는 소프트웨어 개발에 속한다고 믿는다. 예를 들어 FindCarByModel메소드 와 관련하여 이야기하는 경우 저장소의 메소드로 의미가 있으며 Car컬렉션 보다 약간 더 복잡 합니다.
Jesse C. Slicer

2

위의 FindByCarModel 예제에서와 같이 컬렉션을 찾고 슬라이스하기위한 도메인 지향 메소드를 사용하는 것이 편리하지만 랩퍼 콜렉션 클래스를 작성할 필요는 없습니다. 이 상황에서는 일반적으로 확장 메소드 세트를 작성합니다.

public static class CarExtensions
{
    public static IEnumerable<Car> ByModel(this IEnumerable<Car> cars, string model)
    {
        return cars.Where(car => car.Model == model);
    }
}

당신이 원하는대로 당신은 그 클래스에 많은 필터 또는 유틸리티 방법으로 추가, 당신은 당신이 어디서나 사용할 수있는 IEnumerable<Car>것을 포함하는 ICollection<Car>, 배열 Car, IList<Car>

우리의 영속성 솔루션에는 LINQ 공급자가 있기 때문에 나는 종종 on과 return 작동하는 유사한 필터 메소드를 만들 IQueryable<T>것이므로 이러한 작업을 리포지토리에도 적용 할 수 있습니다.

.NET의 관용구 (물론 C #)는 1.1 이후로 많이 바뀌 었습니다. 사용자 지정 컬렉션 클래스를 유지 관리하는 것은 쉬운 일 CollectionBase<T>이 아니므로 도메인 별 필터 및 선택기 메서드 만 있으면 확장 메서드 솔루션을 사용하지 않아도 상속을 받을 수 있습니다.


1

다른 항목의 컬렉션을 보유하기위한 특수 클래스를 만드는 유일한 이유는 가치있는 것을 추가 할 때, 인스턴스 IList또는 다른 유형의 컬렉션 에서 캡슐화 / 상속하는 것 이상이어야한다고 생각 합니다.

예를 들어, 귀하의 경우 짝수 / 고르지 않은 로트 공간에 주차 된 자동차의 하위 목록을 반환하는 함수를 추가하는 경우도 있습니다. 기능은 한 번만 사용되며 요점은 무엇입니까? 키스 !

자, 당신이 많은 분류 / 찾기 방법을 제공 할 계획이라면, 이것이 특별한 컬렉션 클래스에서 그것이 속해야하기 때문에 이것이 유용 할 것이라고 생각합니다. 이 방법은 일부 "찾기"쿼리의 복잡성이나 정렬 / 찾기 방법으로 수행 할 수있는 모든 작업을 "숨기는"좋은 방법입니다.


조차, 나는 그 방법을 메인에 포함시킬 수 있다고 생각합니다.Class
Luis

그렇습니다, 정말로 ... 당신은 할 수 있습니다
Jalayn

-1

다음 옵션을 선호하므로 컬렉션에 메소드를 추가하고 목록의 이점을 사용할 수 있습니다.

public class CarCollection:List<Car>
{
    public Car FindCarByModel(string model)
    {
        // code here
        return new Car();
    }
}

C # 7.0처럼 사용할 수 있습니다.

public class ParkingLot
{
    public CarCollection Cars { get; set; }=new CarCollection();
    //some other properties
}

또는 당신은 그것을처럼 사용할 수 있습니다

public class ParkingLot
{
   public ParkingLot()
   {
      //initial set
      Cars =new CarCollection();
   }
    public CarCollection Cars { get; set; }
    //some other properties
}

-@Bryan 주석 덕분에 일반 버전

   public class MyCollection<T>:List<T> where T:class,new()
    {
        public T FindOrNew(Predicate<T> predicate)
        {
            // code here
            return Find(predicate)?? new T();
        }
       //Other Common methods
     }

그리고 당신은 그것을 사용할 수 있습니다

public class ParkingLot
{
    public MyCollection<Car> Cars { get; set; }=new MyCollection<Car>();
    public MyCollection<Motor> Motors{ get; set; }=new MyCollection<Motor>();
    public MyCollection<Bike> Bikes{ get; set; }=new MyCollection<Bike>();
    //some other properties
}

List <T>에서 상속하지 않음
Bryan Boettcher

@Bryan, 당신은 질문은 일반 컬렉션이 아닙니다. 일반 컬렉션에 대한 답변을 수정하겠습니다.
Waleed AK

1
@WaleedAK 당신은 여전히 ​​그것을했다-List <T>에서 상속하지 마십시오 : stackoverflow.com/questions/21692193/why-not-inherit-from-listt
Bryan Boettcher

@Bryan : 링크를 읽으면 언제 허용됩니까? List <T> 메커니즘을 확장하는 메커니즘을 빌드 할 때 , 추가 재산이없는 한 괜찮습니다
Waleed AK
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.