동일한 방법으로 객체를 두 번 전달하거나 결합 된 인터페이스로 통합 하시겠습니까?


15

디지털 보드와 대화 한 후 데이터 파일을 만드는 방법이 있습니다.

CreateDataFile(IFileAccess boardFileAccess, IMeasurer boardMeasurer)

다음 boardFileAccessboardMeasurera의 같은 인스턴스있는 Board객체가 구현 모두 IFileAccessIMeasurer. IMeasurer이 경우 보드의 한 핀을 활성화하여 간단한 측정을 수행하는 단일 방법에 사용됩니다. 이 측정 값의 데이터는를 사용하여 보드에 로컬로 저장됩니다 IFileAccess. Board별도의 프로젝트에 있습니다.

CreateDataFile빠른 측정을 한 다음 데이터를 저장하여 한 가지 작업을 수행하고 동일한 방법으로 두 작업을 수행하는 것이 다른 사람 에게이 코드를 사용하여 측정하고 파일을 작성 해야하는 것이 더 직관적 이라는 결론에 도달했습니다. 별도의 메소드 호출로.

나에게 같은 객체를 메소드에 두 번 전달하는 것이 어색한 것 같습니다. 나는 로컬 인터페이스 것을 고려했습니다 IDataFileCreator확장합니다 IFileAccessIMeasurer다음이 포함 된 구현이 Board단지 필요한 호출 예를 Board방법을. 동일한 보드 객체가 항상 측정 및 파일 쓰기에 사용된다는 것을 고려할 때 동일한 객체를 메소드에 두 번 전달하는 것은 나쁜 습관입니까? 그렇다면 로컬 인터페이스를 사용하고 적절한 솔루션을 구현하고 있습니까?


2
사용중인 이름에서 코드의 의도를 파악하는 것은 불가능합니다. IDataFileCreator라는 인터페이스는 CreateDataFile이라는 메서드에 전달되고 있습니다. 그들은 데이터를 유지하는 책임을 놓고 경쟁하고 있습니까? 어쨌든 CreateDataFile은 어떤 클래스입니까? 측정은 지속적인 데이터와 관련이 없으므로 많은 것이 분명합니다. 귀하의 질문은 코드와 관련된 가장 큰 문제에 관한 것이 아닙니다.
Martin Maat

파일 액세스 객체와 측정기 객체가 서로 다른 객체 일 수 있습니까? 나는 그렇다고 말할 것입니다. 지금 변경 하면 네트워크에서 측정을 지원하는 버전 2로 다시 변경해야 합니다.
user253751

2
여기 또 다른 질문이 있습니다. 왜 데이터 파일 액세스와 측정 개체가 처음에 동일한가?
user253751

답변:


40

아니요, 이것은 완벽합니다. 단지 현재 응용 프로그램과 관련 하여 API가 과도하게 엔지니어링되었음을 의미합니다 .

그러나 이는 데이터 소스와 측정기가 다른 유스 케이스 가 결코 존재하지 않음을 증명하지 않습니다 . API의 요점은 응용 프로그램 프로그래머 가능성을 제공하는 것입니다. 순 이해도가 떨어지도록 API를 복잡하게하지 않으면 API 사용자가 수행 할 수있는 작업을 인위적으로 제한해서는 안됩니다.


7

@KilianFoth의 답변에 동의 하면 이것이 완벽합니다.

그래도 원하는 경우 두 인터페이스를 모두 구현하는 단일 객체를 사용하는 메서드를 만들 수 있습니다.

public object CreateDataFile<T_BoardInterface>(
             T_BoardInterface boardInterface
    )
    where T_BoardInterface : IFileAccess, IMeasurer
{
    return CreateDataFile(
                boardInterface
            ,   boardInterface
        );
}

인수가 다른 객체 일 필요가있는 일반적인 이유는 없으며, 메소드가 인수가 달라야하는 경우에는 계약이 명확해야하는 특별한 요구 사항이됩니다.


4

CreateDataFile빠른 측정을 한 다음 데이터를 저장하여 한 가지 작업을 수행하고 동일한 방법으로 두 작업을 수행하는 것이 다른 사람 에게이 코드를 사용하여 측정하고 파일을 작성 해야하는 것이 더 직관적 이라는 결론에 도달했습니다. 별도의 메소드 호출로.

실제로 이것이 당신의 문제라고 생각합니다. 이 방법은 한 가지 일을 하지 않습니다 . 다른 장치에 대한 I / O와 관련된 두 가지 별개의 작업을 수행하고 있습니다. 두 가지 모두 다른 객체로 오프로드됩니다.

  • 측정 값 가져 오기
  • 결과를 어딘가에 파일로 저장

두 가지 다른 I / O 작업입니다. 특히, 첫 번째 파일 시스템은 어떤 식 으로든 파일 시스템을 변경하지 않습니다.

실제로, 우리는 중간 단계가 내포되어 있음에 유의해야합니다.

  • 측정 값 가져 오기
  • 측정을 알려진 형식으로 직렬화
  • 직렬화 된 측정 값을 파일로 저장

API는 이들 각각을 개별적으로 어떤 형태로 제공해야합니다. 발신자가 어디에도 저장하지 않고 측정을 원하지 않는다는 것을 어떻게 알 수 있습니까? 그들이 다른 소스로부터 측정을 받고 싶지 않다는 것을 어떻게 알 수 있습니까? 장치 이외의 다른 곳에 저장하고 싶지 않다는 것을 어떻게 알 수 있습니까? 작업을 분리해야 할 이유가 있습니다. (A)에서 맨손으로 최소, 각각의 조각은해야 가능한 모든 호출자. 사용 사례에서 요구하지 않는 경우 파일에 측정 값을 쓰도록 강요해서는 안됩니다.

예를 들어 이와 같은 작업을 분리 할 수 ​​있습니다.

IMeasurer 측정 값을 가져 오는 방법이 있습니다.

public interface IMeasurer
{
    IMeasurement Measure(int someInput);
}

측정 유형은 string또는 과 같은 단순한 것일 수 있습니다 decimal. 인터페이스 또는 클래스가 필요하다고 주장하지는 않지만 여기에서 예제가 더 일반적입니다.

IFileAccess 파일을 저장하는 몇 가지 방법이 있습니다.

interface IFileAccess
{
    void SaveFile(string fileContents);
}

그런 다음 측정을 직렬화하는 방법이 필요합니다. 이를 측정을 나타내는 클래스 또는 인터페이스에 구축하거나 유틸리티 메소드를 사용하십시오.

interface IMeasurement
{
    // As part of the type
    string Serialize();
}

// Utility method. Makes more sense if the measurement is not a custom type.
public static string SerializeMeasurement(IMeasurement m)
{
    return ...
}

이 직렬화 작업이 아직 분리되어 있는지 확실하지 않습니다.

이러한 분리는 API를 향상시킵니다. 이를 통해 호출자는 I / O 수행에 대한 선입견을 강요하지 않고 필요한 내용과시기를 결정할 수 있습니다 . 유용하다고 생각하든, 발신자에게는 유효한 작업 을 수행 할 수있는 제어 기능이 있어야합니다 .

각 작업에 대해 별도의 구현 CreateDataFile이 있으면 메서드가 간단합니다.

fileAccess.SaveFile(SerializeMeasurement(measurer.Measure()));

특히,이 모든 작업을 수행하면 메서드에 거의 가치가 없습니다. 위의 코드 줄은 호출자가 직접 사용하기 어렵지 않으며 메서드는 순전히 편의를위한 것입니다. 이 옵션선택 사항 입니다. 그리고 이것이 API가 작동하는 올바른 방법입니다.


모든 관련 부분이 제외되고 해당 방법이 단지 편리함을 인정한 후에는 다음과 같이 귀하의 질문을 바꾸어야합니다.

발신자에게 가장 일반적인 사용 사례는 무엇입니까?

요점은 같은 보드에서 측정하고 쓰는 것과 같은 일반적인 사용 사례를 약간 더 편리하게 만드는 것이라면 Board수업에서 직접 사용할 수 있도록하는 것이 좋습니다 .

public class Board : IMeasurer, IFileAccess
{
    // Interface methods...

    /// <summary>
    /// Convenience method to measure and immediate record measurement in
    /// default location.
    /// </summary>
    public void ReadAndSaveMeasurement()
    {
        this.SaveFile(SerializeMeasurement(this.Measure()));
    }
}

이것이 편의성을 향상시키지 못하면 방법을 전혀 신경 쓰지 않을 것입니다.


이것은 편리한 방법이기 때문에 다른 질문이 하나 있습니다.

해야 IFileAccess인터페이스는 측정 유형 및 직렬화하는 방법에 대해 알아? 그렇다면 다음에 메소드를 추가 할 수 있습니다 IFileAccess.

interface IFileAccess
{
    void SaveFile(string fileContents);
    void SaveMeasurement(IMeasurement m);
}

이제 발신자가이 작업을 수행합니다.

fileAccess.SaveFile(measurer.Measure());

질문에서 생각한 것처럼 편리한 방법보다 짧고 분명합니다.


2

소비자는 단일 품목으로 충분할 때 품목 쌍을 처리 할 필요가 없습니다. 귀하의 경우에는의 호출 때까지 거의 없습니다 CreateDataFile.

제안하는 잠재적 솔루션은 결합 된 파생 인터페이스를 만드는 것입니다. 그러나이 방법에는 두 인터페이스를 모두 구현하는 단일 객체가 필요합니다. 이는 다소 제한적이며, 기본적으로 특정 구현에 맞게 사용자 정의되어 있기 때문에 누출이 발생할 수 있습니다. 누군가가 두 개의 인터페이스를 별도의 객체로 구현하려면 얼마나 복잡한 지 고려하십시오. 다른 객체로 전달하려면 인터페이스 중 하나의 모든 메소드를 프록시해야합니다. (FWIW의 또 다른 옵션은 하나의 객체가 파생 된 인터페이스를 통해 두 개의 인터페이스를 구현해야하는 대신 인터페이스를 병합하는 것입니다.)

그러나, 구현에 대해 덜 제한적이거나 / 또는 지시하는 다른 접근법은 인 컴포지션 IFileAccess과 쌍을 이루어 IMeasurer그 중 하나가 다른 하나에 바인딩되고 참조되도록하는 것이다. (이것은 현재 페어링을 나타 내기 때문에 이들 중 하나의 추상화를 다소 증가시킵니다.) 그런 다음 CreateDataFile참조 중 하나만 가져 와서 IFileAccess필요에 따라 다른 참조를 얻을 수 있습니다. 두 인터페이스를 모두 구현하는 객체로서의 현재 구현은 단순히 return this;컴퍼 지션 참조, 여기서 getter에 대한 것 IMeasurer입니다 IFileAccess.

개발 중 어느 시점에서 페어링이 거짓으로 판명되는 경우, 즉 때때로 동일한 측정 값으로 다른 측정기를 사용하는 경우, 동일한 페어링을 수행 할 수 있지만 대신 더 높은 수준에서 추가 인터페이스를 도입 할 수 있습니다. 파생 된 인터페이스가 아니라 파생 된 구성이 아닌 파일 액세스와 측정기를 쌍으로 연결하는 두 개의 게터가있는 인터페이스입니다. 그런 다음 소비하는 클라이언트는 페어링이 유지되는 한 자신이 관심을 가질 수있는 하나의 항목과 필요할 때 처리 할 개별 객체 (새 페어링을 구성하기 위해)를 갖습니다.


또 다른 참고로, 나는 누가 누구의 소유인지 물어볼 수 있으며 CreateDataFile,이 제삼자는 누구인지에 대한 질문을합니다. 우리는 이미 일부 사용자 클라이언트가 그 원용 CreateDataFile의 소유 객체 / 클래스 CreateDataFileIFileAccessIMeasurer. 상황에 대한 더 큰 관점을 볼 때 때때로, 더 나은 대안으로 조직이 나타날 수 있습니다. 문맥이 불완전하기 때문에 여기서는 어려우므로 생각할 음식입니다.


0

일부는 그 위로 가져왔다 CreateDataFile너무 많이하고있다. Board파일에 액세스하는 것이 보드의 나머지 부분과는 별도의 관심사처럼 보이므로 대신 너무 많은 일을하고 있다고 제안 할 수 있습니다 .

그러나 이것이 실수가 아니라고 가정하면 더 큰 문제는이 경우 클라이언트가 인터페이스를 정의해야한다는 것 CreateDataFile입니다.

인터페이스 독방 원리는 클라이언트가 필요한 것보다 인터페이스의 더 의존 할 필요가 없습니다 상태. 이 다른 대답 에서 문구를 빌려 보면 이것은 "클라이언트가 필요로하는 것에 의해 인터페이스가 정의된다"고 표현 될 수 있습니다.

지금, 사용하는 인터페이스이 특정 클라이언트를 구성하는 것이 가능 IFileAccess하고 IMeasurer다른 답변을 제안하지만, 궁극적으로,이 클라이언트는 인터페이스가 그것을 위해 맞춤형 있어야합니다.


@Downvoter-이것은 어떻습니까? 부정확하거나 개선 할 수 있습니까?
Xtros
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.