2014-12-15 2 views
4

특히 Façade 패턴을 구현하려고 할 때 C#의 저장소 패턴을 사용하는 데 문제가 있습니다. 내 개념은 다음과 같습니다.저장소 패턴의 제네릭을 사용하는 다형성

처음으로 일반 저장소를 시작했을 때 모든 CRUD 작업이 하나의 파일 (및 관련 인터페이스가 별도의 단일 파일에 있음)로 시작했습니다. 하지만 솔리드 원칙과 특히 ISP 원칙 때문에 모든 인터페이스를 별도의 파일로 분리하고 클래스와 마찬가지로 수행하기로 결정했습니다.

예를 들어 하나의 파일에서 다양한 Create, Read ... 메소드 및 다른 GenericRepo와 함께 IGenericRepo를 사용하는 대신. 나는 공통점이있는 모든 것을하기 위해 기지 레포를 가지고 그들 모두를 분리했다. 그래서 나는 ICreateRepo, IReadOneRepo, IReadManyRepo ... 등으로 끝났습니다. ,

 public T Read(int id) 

  • 을 지정된 ID로 하나의 레코드를 읽기 : 시간이 경과으로

    는 내 프로젝트의 요구가 성장하고, 나 자신이 작업은 "읽기"여러 필요 발견

    • 여러 값으로 전달해야하는 복합 원자가있을 수있는 단일 레코드를 읽습니다. EF Find Method ...와 같이 작동합니다.
       public T Read(params object[] keyValues) 
      
      • 반환
      EF의 같은 모든 필드에서 검색을 기반으로 최초의 기록을 ... 어디 매개 변수와 같은했다 방법, ...
     public T Read(Expression<Func<T>,bool>> predicate) 
    

    내가 필요한 상황을 발견 할 때까지는 괜찮 았어. 여러 레코드를 읽고 해당 조건과 일치하는 모든 레코드 목록을 반환합니다. 본질적으로 읽기 연산은 마지막에 언급 한 것과 동일한 메소드 서명을 가지며 리턴 유형 만 다릅니다. 하나는 단일 엔티티를 반환하고 다른 엔티티는 일치하는 엔티티 목록을 반환했습니다.

    고유 한 클래스로 구분되는 동안 아무런 문제가 없습니다. 그러나 나는 MVC를 사용하는 컨트롤러에서 6 개 또는 9 개의 저장소에 대한 긴 목록을 발견했으며,이를 단일 일반에 대한 것과 같이 단순화하고자했습니다. 그래서 저는 Façade 패턴으로 돌아 섰습니다.

    이제 읽기 기능을 가져 오면 서명이 동일하기 때문에 다형성 문제가 발생합니다.

    //ReadOne 1 
        public T Read(int id) 
        { } 
        //ReadOne 2 
        public T Read(params object[] keyValues) 
        { } 
        //ReadOne 3 *** Signature same as search except for return type. 
        public T Read(Expression<Func<T, bool>> predicate) 
        { 
         //SingleOrDefault used purposefully instead of FirstOrDefault to cause exception if 
         //there is more than one instance that meets the predicate. 
         return dbSet.Where(predicate).SingleOrDefault<TEntity>(); 
        } 
    
        //Search 
        public IQueryable<T> Read(Expression<Func<T, bool>> predicate) 
        { 
         return dbSet.Where(predicate); 
        } 
    
        //ReadAll 
        public IQueryable<T> Read() 
        { } 
    

    언급 한 바와 같이 ... 별도의 파일로 분리 된 경우 필요에 따라 명시 적으로 호출되므로 별개의 파일로 구분됩니다. 그러나 Façade 패턴을 사용하여 코드를 단순화하고자합니다.

    나는 물론 반환 유형에 따라 다형성이 없다는 문제가 있습니다. 나는 이것을 이해하고 그 이유를 충분히 이해한다.

    검색 끝에 선택적 bool 매개 변수를 추가하려고 생각했습니다. 그러나 그것은 어떤 이유로 든 기분이 좋지 않습니다. 뭔가가 ...

    //Search 
        public IQueryable<T> Read(Expression<Func<T, bool>> predicate, bool returnOne = false) 
        { } 
    

    내 질문은이 제한 사항을 해결하는 방법에 대한 아이디어가 있습니까?

+2

:

public static class Predicates { public static ExpressionToFindSingle<T> ForSingle<T>(this Expression<Func<T, bool>> predicate) { return new ExpressionToFindSingle<T>(predicate); } } 

그런 다음, 클래스는 (그들의 서명을 표시)이 방법을 가질 수 있습니다 : 발신자에 대한 것들을 간단하게하려면, 당신은 또한 더 쉽게 래퍼를 만들 Expression<..>을 확장 할 수 있습니다 'T'를 반환하는 것과'IQueryable '을 반환하는 것의 차이점을 알아야 할 필요가 있습니다. 그 방법은 다른 방법으로 간단히 지정해야합니다. 예 : 'Read()'와'ReadQueryable()'또는 그와 비슷한 것. 이것이 가능하지 않다면 질문을 상당히 단순화하여 질문을보다 정확하게 설명해야합니다. 나는 디자인 패턴을 언급 할 필요가 없다는 것을 의심 할 여지가 없다. 당신의 사용법을 정교하게 생각하고, 당신이 가지고있는 _specific_ 질문을 표현할 필요가 없다. http://stackoverflow.com/help/how-to-ask –

+0

@PeterDuniho - 모든 메소드의 이름을 바꿀 경우 다형성의 요점은 무엇입니까? SOLID 원칙은 DIP를 다른 원칙으로 언급했습니다. 효과적으로 내 부름 수업을 단단히 결합 시켜서는 안된다는 의미입니다. 당신이 제안하는, 이름 바꾸기 방법은 이것에 반대 할 것입니다. 디자인 패턴에 대한 의견에 관해서는이 질문에 가장 중요합니다. 그래서 질문 지침에 뭔가 언급하고 있습니다 ... 나는 3 년이 넘었습니다. 디자인 패턴에 대해 언급하지 않는 방법을 묻는 링크에서 본 적이 없었습니다. 그러나 귀하의 의견에 감사드립니다. –

+0

질문을 개선하는 방법에 대한 구체적인 제안 사항이 있으면 기꺼이 수정 해 드리겠습니다. 나는 당신의 연결 고리를보고 질문이 명확하다는 것을 느낀다. 그래서 당신의 경멸은 혼란 스럽습니다. 그러나, 나는 디자인 패턴을 많이 사용하고 질문과 관련이 있다고 느끼기 때문에 전체적으로 그렇게 널리 퍼져 있습니다. 귀하의 디자인 패턴 이해 부족으로 인해 귀하의 답변 능력이 제한 될 경우 사과드립니다. 이해를 돕고 답을 장려하기 위해 질문을 개선 할 수 있다면 조언 해주십시오. 닫기 및 아래 표를 설명하는 시간을내어 주셔서 감사합니다. –

답변

3

Read을 반환하는 단일 엔터티 이름을 ReadSingle으로 바꿀 수 있습니다. 이는 조건자를 매개 변수로 사용하더라도 단일 엔터티 만 반환한다는 것을 명확히합니다. 의 이름을 먼저 변경하려고합니다..

다른 옵션을 원하면 매개 변수의 메소드 서명을 구분할 수 있습니다. 당신은 단일 반환 괴짜 경우에 대한 술어 래퍼 유형을 만들 수 있습니다 변환 연산자 감안할 때

public class ExpressionToFindSingle<T> { 
    private Expression<Func<T, bool>> predicate; 
    public ExpressionToFindSingle(Expression<Func<T, bool>> predicate) { 
    this.predicate = predicate; 
    } 
    public static implicit operator Expression<Func<T, bool>>(ExpressionToFindSingle<T> wrapper) { 
    return wrapper.predicate; 
    } 
} 

, 당신은 직접 술어로 래퍼를 사용할 수 있습니다. 발신자 이후

T Read(ExpressionToFindSingle<T> predicate); 

IQueryable<T> Read(Expression<Func<T, bool>> predicate); 
+0

무슨 일이 일어나고 있는지 완전히 이해하기 위해 두 번 읽어야했습니다. 그러나 어려움은 어딘가에 자리 잡고 있습니다. 그래서 나는 그것을 아주 좋아합니다. 명확한 코드로 이어지고 지금까지 본 최고의 솔루션이라고 확신합니다. 내가 찾던 주된 일은 이름을 유지하고 (다형성 사용), 아주 명백한 방법으로 서명을 기반으로 차별화 할 수있는 방법이었습니다. 이 솔루션은이를 제공합니다. 반환 유형은 소비자가 반환 할 내용을 알 수 있도록하기에 충분합니다 (단일/여러). 이렇게 좋은 일 및 당신의 대답을위한 감사합니다. –

+0

그러나 나는 질문이 있습니다. 그것의 대부분은 명명법에 이르기까지 생각합니다. SinglePredicateExpression 대 ​​MultiPredicateExpression이라는 이름은 다소 혼란 스럽습니다. 현재 시스템에서 가지고있는 문제는 다형성 시그니처가 같고 반환 유형 만 ReadOne 3과 Search가 다르다는 것입니다. 그러나 둘 중 하나를 사용하지 않으면 단일 또는 다중 조건자를 전달하고 매번 원하는 결과를 얻을 수 있습니다. 이 방법으로 술어의 이름을 지정하면이를 사용하는 메소드가 예를 들어 readOne 3의 경우 단일 술어로 제한된다는 것을 알 수 있습니다. –

+0

ReadOne 3에 여러 술어를 전달해야하는 상황이 발생하여 설명 된대로 첫 번째 결과가 반환됩니다. 그 반대도 마찬가지입니다. 어쩌면 내가 놓친 것이 있을까요? 메소드가 하나의 레코드만을 반환하기 때문에 그것이 단일 입력 만 가질 것이라는 의미는 아닙니다. 단일 레코드를 찾기 위해 여러 필드를 검색해야 할 수도 있다고 합리적으로 가정합니다. 검색의 경우도 마찬가지입니다. 하나의 조건 자, 즉 ID가 5 인 고객에게 속한 모든 인보이스 만 삽입하는 경우에도 여러 레코드를 반환하는 것이 일반적입니다. –

0

IQueryable 만 반환합니다. 엔티티가 하나만 반환되는 경우도 있습니다. IQueryable에 하나의 레코드 만 있으면 어떻게됩니까? 나는 내가 추측 할 필요성을 보지 않고있다 ..

당신의 매개 변수와 같은 것. 왜 당신은 단일 대 배열에 대한 명시적인 경우가 필요합니까? 그냥 배열을 가지고.

returnOne 플래그는 전혀 의미가 없습니다. 이쪽을 봐 ... 네가 돌아올 수 있을까? 두? returnThree? 아니오. 그 시점에서 디자인에 결함이 있기 때문입니다. 또한 이것이 패턴을 참조 할 필요가 없다는 다른 의견에 동의합니다. 실제로 이것은 모범 사례 문제입니다.

+0

당신의 논리와 관련된 문제는 ... 왜 단일 항목 만 항상 필요하다는 것을 알 때 (예 : PK로 단일 레코드를 읽는 경우와 같이) 쿼리 가능한 배열 또는 목록을 반환하는 것입니다. 이것은 소비자를 혼란스럽게하고 내가 아는 어떤 모범 사례와도 분명히 상충됩니다. 한 항목 만 반환하는 경우. 내부적으로 단일 항목으로 필터링하는 방법과 상관없이 단일 항목의 모음을 반환하는 확실히 나쁜 부두입니다. 이것은 제 의견이 아니지만 업계 최고의 모범 사례입니다. 그러나 의견 대신 답변 형식으로 아이디어를 제출해 주셔서 감사합니다. 시간 내 주셔서 감사합니다. –

+0

그러나 ReturnOne 등의 특수 매개 변수를 추가 할 필요가 없다는 것에 동의합니다. 이는 모범 사례에도 위배되며 귀하가 지정한 동일한 이유로 동의합니다. 지금까지 볼 수있는 가장 좋은 해결책은 이름 바꾸기에 대한 Grax 주석입니다. –

+0

이 경우에는 대부분 두 번만 호출하면됩니다. "GetEntity"및 "GetEntities". 단일 반환 값은 좋은 값입니다. 그것의 "나쁜 부두"하나의 항목으로 컬렉션을 반환합니다. 컬렉션에는 항상 하나의 항목 만 있습니다. 그러나 만약 당신이 정말로 하나의 리턴 타입을위한 기능을 원한다면 (필요하다면), 이전에 말했듯이 당신은 2를 가질 것입니다. 또한 단순한 디자인은 API를 혼란스럽게 만들지 않으므로이 코드를 사용하는 개발자는 무엇을해야할지 알 수 있습니다. 그게 전부 야. 이 모든 특수한 경우를 복잡하게 만들 필요가없는 것은 실제로 복잡합니다. – PJC

관련 문제