2017-02-14 16 views
2

코드에서 일부 코드 부분이 현재 소프트웨어 세션에 의존하는 구조가 있습니다. 소프트웨어 세션은 구성에 의해 종속성이 주입되는 여러 도우미 객체를 포함합니다.C#에서 컴포지션 인터페이스 단순화

한 예로 데이터 저장소에 대한 액세스 권한이있는 IRepository가 주입되었습니다. IRepository에는 IDbContext를 통해 데이터베이스에 다시 쓰는 DatabaseContext가 포함되어 있습니다.

SoftwareSession은 게이트웨이로 작동하는 데이터베이스의 모든 방법에 액세스하기위한 유일한 기본 인프라입니다. 이것은 데이터베이스에 객체를 쓰고 싶을 때 (예를 들어 WriteCar), 3 개의 인터페이스, 2 개의 함수가 작성된 객체에 위임하고 1 개의 함수가 구현되어야한다는 것을 의미합니다. 아래의 코드에서 명확하게 설명합니다. WriteCar 서명은 3 개의 인터페이스 (IRepository, ISoftwareSession, IDbContext), 복합 객체 관련 함수 및 실제 구현 장소 (IDbContext)를 단순히 호출하는 2 개의 장소 (Repository, SoftwareSession)로 동일하게 정의됩니다.

즉, 리팩토링하거나, 코드를 이동하거나, 기능을 추가하거나, 기능 서명을 변경하고자 할 때, 한 기능에 대해 항상 6 개를 변경해야합니다.

이것은 테스트 가능성을 향상시키는 최상의 환경을 제공한다고 생각하며 소프트웨어 세션이 저장소에 대한 액세스를 래핑하고 저장소가 데이터 컨텍스트에 대한 액세스를 래핑하는 최상의 방법을 따릅니다. 아직 한 번 더 쓸 수있는 방법이 있는지 계속 질문하고 있습니다. , 또는 아래의 코드에서 일부 개념에 대한 오해가 있습니까?

구조적으로 유지 관리가 쉬운이 구현 방법은 무엇입니까? 어쩌면 람다 (lambdas) 나 델리게이트 (delegate)의 영리한 방법을 사용하여 각각의 새로운 기능에 대해 작성된 코드의 양을 줄일 수 있습니까? 또는 Visual Studio, Resharper 등을 사용하는 일종의 템플릿 메커니즘에서이 코드를 쉽게 생성 할 수있는 라이브러리 (예 : 자동 완성 프로그램과 같은 DTO) 또는 도구가 있습니까?

여기에 개념이 혼란 스럽다면 알려주십시오. 제 동료 중 일부는 비슷한 견해를 가지고 있다는 것을 알고 있습니다. 그렇다면 다른 사람들의 오해를 분명히하는 것이 도움이 될 수 있습니다. 한 가지 들어

public class SoftwareSession : ISoftwareSession 
{ 
    ... 
    IRepository repository; 
    public void WriteCar(Car car){ 
     repository.WriteCar(car); 
    } 
    ... 
} 

public interface ISoftwareSession{ 
    ... 
    void WriteCar(Car car); 
    ... 
} 


public class Repository : IRepository{ 
    ... 
    IDbContext context; 
    public void WriteCar(Car car){ 
     context.WriteCar(car); 
    } 
    ...   
} 

public interface IRepository{ 
    ... 
    void WriteCar(Car car); 
    ... 
} 

public class MyDbContext : IDbContext{ 
    ... 
    public void WriteCar(Car car){ 
     //The Actual Implementation here. 
     ... 
    } 
    ... 
} 

public interface IDbContext{ 
    ... 
    void WriteCar(Car car); 
    ... 
} 
+0

인터페이스 : 그럼 여기

public class Repository : IRepository { IDbContext context; public Repository(IDbContext dbContext) { context = dbContext; } public void WriteCar(Car car) { context.WriteCar(car); } } 

는 구성 루트 상속받을 수 있습니다! 왜'ICarWriter' 인터페이스를 가지지 않고'IRepository : ICarWriter','ISoftwareSession : ICarWriter' 등등을 가지고 계십시오. –

+0

나는이 문제가 소프트웨어 세션 구현에 있다고 믿는다. 이것은 프레임 워크에서 데이터베이스, writeCar, writeCustomer 등으로가는 단일 책임을 위반하는 단일 책임을 위반하는 것입니다.이 클래스에는 acccessor가 있어야합니다. – Dys1

+0

@ BarryO'Kane 동의합니다 - 이것은 인터페이스를 리팩터링하는 방법이며 중복 된 코드 관점을 줄이는 것이 좋습니다. 나는 이것을 단순화하는 다른 가능한 방법을 기꺼이 기다리고있다. – user3141326

답변

1

, 당신의 IDbContextIRepository은 동일합니다. IDbContext을 제거하거나 최소한 IRepository에 선언 된 메소드를 제거하고 싶을 것입니다.

그런 다음 모두 MyDbContextRepositoryIRepository을 구현하는 것이 및 Repository 클래스는 단지 MyDbContext 래퍼가 될 것입니다.

그런 다음 RepositoryMyDbContext으로 착신 전환 만하는 경우 해당 분류가 필요하지 않을 수도 있습니다.

또한 포함 된 저장소로 전화를 착신 전환하는 것 외에는 SoftwareSession에서 아무 것도하지 않는 것으로 나타났습니다. SoftwareSession이 정말로 필요합니까, 아니면 IRepository을 세션 객체를 호출하는 사람에게 직접 넘기는 것이 합리적입니까?

결론은이 구현이 복제 및 전달으로 붐 is다는 것입니다. 그것을 제거하면 전체 모델이 단순 해집니다.

+0

고마워요 조란. IRepository는 여러 개의 DbContext로 인해 추가됩니다 (예 : 한 컨텍스트는 도로 표지판을 볼 수있는 DrivingContext 일 수 있고 다른 컨텍스트는 유지 관리 관련 기능을 구현하는 유지 관리 또는 관리 컨텍스트 일 ​​수 있음). 이 경우 리포지토리는 구현시 다른 컨텍스트의 집계 자 역할을합니다. 내가 소프트웨어 세션을 사용하지 않는다면,이 함수가 호출되는 다른 모든 클래스에 저장소 나 DbContext를 삽입해야 할 것입니다. 그러면 추가 복제가 발생하지 않고 캡슐화가 중단됩니다. – user3141326

0

구성 루트를 보지 않고 구현이 어떻게 작동하는지 완전히 모르겠지만 Inversion of Control (IoC) 컨테이너를 사용하는 것이 좋습니다. ISoftwareSession 구현은 IRepository 인스턴스에만 의존하므로 클래스의 생성자에 입력하면됩니다. IRepository 구현에 대해서도 마찬가지입니다. IDbContext을 생성자에 삽입하기 만하면됩니다.

IoC 컨테이너를 사용하면 애플리케이션을 시작할 때 컴포지션 루트에있는 인터페이스를 구현에 연결하고 의존성을 해결할 때 컨테이너가 필요한 인스턴스를 생성합니다. 그런 다음 컨테이너에서 SoftwareSession의 인스턴스를 가져 오면됩니다.

public class SoftwareSession : ISoftwareSession 
{ 
    IRepository repository; 

    public SoftwareSession(IRepository repository) 
    { 
     this.repository = repository; 
    } 

    public void WriteCar(Car car) 
    { 
     repository.WriteCar(car); 
    } 
} 

그리고이처럼 Repository 구현 :

그래서, 당신은이처럼 SoftwareSession 구현을 바꿀 수

var ioc = new MyIocContainer(); 

// register your interfaces and their associated implementation types with the IoC container 
ioc.Register<ISoftwareSession, SoftwareSession>(); 
ioc.Register<IRepository, Repository>(); 
ioc.Register<IDbContext, MyDbContext>(); 

// resolve the IoC container 
ioc.Resolve(); 

// get your `ISoftwareSession` instance 
var session = ioc.GetConcrete<ISoftwareSession>(); 

var newCar = new Car(); 

session.WriteCar(newCar); 
+0

답변 해 주신 Rory 감사합니다. 나는 이미 질문의 모든 항목에 대해 생성자 삽입과 함께 Ninject를 사용하고 있습니다. 문제는 실제 주입이 아니라 WriteCar 인터페이스 및 구현 위임을이 아키텍처를 사용하는 함수 당 6 개 장소에서 사용하는 것입니다. 나머지 모든 메인 라인 클래스는 생성자를 통해 주입 된 SoftwareSession 만 가지고 있으며 예를 들어 호출합니다. WriteCar 함수를 호출하여 해당 소프트웨어 세션을 호출합니다. 그러나 나는 실제 구현에 도달하기 위해 서명을 6 번 작성/복제해야합니다. – user3141326

+0

"함수 당 6 개 장소에서 WriteCar 인터페이스 및 구현 위임을 사용하는 것"이 ​​무슨 뜻인지 이해할 수 없습니다. 'WriteCar' 인터페이스가 보이지 않습니다. "구현 위임"이란 무엇입니까? 그리고 당신이 말하는 함수 (method?)에서 "six places"는 어디에 있습니까? 당신이 제공 한 코드에서 나는 그것을 보지 못했습니다. 그래서 나는 혼란 스럽습니다. –

+0

이 로리를 명확히하지 못해 죄송합니다. 문제도 해결할 것입니다. WriteCar 시그니처는 3 개의 인터페이스 (IRepository, ISoftwareSession, IDbContext), 구현되지 않은 2 곳 (Repository, SoftwareSession), 합성 된 객체 관련 함수 및 실제 구현 장소 (IDbContext)를 동일하게 정의합니다. – user3141326