멤버 숨기기 전용 목적으로 명시 적 인터페이스 구현을 사용해야하는 이유는 무엇입니까?


11

C #의 복잡성에 대한 연구 중 하나에서 명시 적 인터페이스 구현에 관한 흥미로운 구절을 발견했습니다.

While this syntax is quite helpful when you need to resolve name clashes, you can use explicit interface implementation simply to hide more "advanced" members from the object level.

사용을 허용 object.method()하거나 캐스팅을 요구하는 것의 차이는 ((Interface)object).method()미숙 한 눈에 평균적인 난독 화처럼 보입니다. 텍스트는 이것이 객체 레벨에서 Intellisense에서 메소드를 숨길 것이라고 지적했지만 이름 충돌을 피할 필요가 없다면 왜 그렇게 하고 싶 습니까?


답변:


12

인터페이스가 클래스의 일부로 실제로 이해되지 않는 메소드를 클래스로 강제 실행하는 상황을 상상해보십시오. 이는 인터페이스가 특히 커서 인터페이스 분리 원리를 위반할 때 발생할 수 있습니다.

이 클래스는 인터페이스를 구현해야하지만 타당하지 않은 메소드로 눈에 잘 띄는 공용 인터페이스를 오염시키는 대신 명확하게 사용하지 않으려는 메소드를 명시 적으로 구현할 수 있습니다. 클래스의 눈에 잘 띄는 공개 인터페이스는 클래스 사용 방법이며, 인터페이스를 통해 클래스에 액세스 할 때 명시적인 구현이 있습니다.


6
그냥 나인가요, 아니면 이건 끔찍한 생각처럼 들리나요?
케빈 페노

5
@ 케빈, 어떻게? 때로는 인터페이스가 제어 할 수 없으므로 인터페이스를 사용해야합니다. 압도적 인 인터페이스의 손상을 완화하는 것이 합리적입니다.
Chris Pitman 2

1
현실 세계가 올바른 방식으로 일을하는 데 방해가된다는 점을 지적한 +1. @ Kevin 예, 그것은 끔찍한 아이디어이지만 때로는 선택의 여지가 없으며 슬로프와 함께 일 해야합니다. 실제로 제대로 할 수 없을 때 숨기고 올바르게 작업하는 외관을 만드는 것이 좋습니다 .
Wayne Molina

@ 웨인, 나는 그러한 시스템을 원하거나 사용하려는 당신의 추론을 이해합니다. 지옥, 아마 당신이 말한 경우에 그것을 사용했을 것입니다. 내 짧은 의견이 실제로 이것이 부적절하다는 것을 지적 한 것 같습니다. 왜 언어로 허용합니까?
Kevin Peno

1
과도한 인터페이스 분리는 구성 및 집계에 주요 장애물이 될 수 있습니다. 예를 들어, 구현이 IEnumerable<T>다른 두 개의 연결로 작동 하기를 원한다고 생각하십시오 . 경우 IEnumerable<T>의 수는 알려져 여부를 말할 수있는 속성을 포함, 잠재적으로 무한, 또는 둘, 방법과 함께 자사의 개수가 여러 집계 클래스 무엇인지 물어 보지에 IEnumerable<T>효율적으로 일부 그 경우의 수를보고 할 수있는 연결로 및 동작합니다을 캡슐화 된 컬렉션은 그들의 수를 알고있었습니다.
supercat

4

내가 찾은 가장 유용한 응용 프로그램은 공장 구현입니다. 대부분의 경우 팩토리 내부에서 변경 가능하지만 외부 클래스로는 변경할 수없는 클래스를 작성하는 것이 유용합니다. 필드와 세터를 비공개로 만들고 게터를 공개 멤버로 노출함으로써 내부 클래스를 사용하여 Java에서 쉽게 구현할 수 있습니다. 그러나 C #에서는 동일한 것을 달성하기 위해 명시 적 인터페이스를 사용해야했습니다. 더 설명하겠습니다 :

Java에서 내부 클래스와 외부 클래스는 서로의 개인 멤버에 액세스 할 수 있으므로 클래스가 매우 밀접하게 관련되어 있으므로 완전히 이해됩니다. 그것들은 같은 코드 파일에 있으며 아마도 같은 개발자에 의해 개발되었을 것입니다. 이는 팩토리가 내부 클래스의 개인 필드 및 메소드에 여전히 액세스하여 값을 수정할 수 있음을 의미합니다. 그러나 외부 클래스는 공개 게터를 제외하고는이 필드에 액세스 할 수 없습니다.

그러나 C #에서 외부 클래스는 내부 클래스의 개인 멤버에 액세스 할 수 없으므로 개념이 직접 적용되지 않습니다. 외부 클래스에서 개인 인터페이스를 정의하고 내부 클래스에서 명시 적으로 구현하여 명시 적 인터페이스를 해결 방법으로 사용했습니다. 이런 식으로 외부 클래스 만이 Java에서와 같은 방식으로이 인터페이스의 메소드에 액세스 할 수 있습니다 (그러나 필드가 아닌 메소드 여야 함).

예:

public class Factory
{
    // factory method to create a hard-coded Mazda Tribute car.
    public static Car CreateCar()
    {
        Car car = new Car();

        // the Factory class can modify the model because it has access to
        // the private ICarSetters interface
        ((ICarSetters)car).model = "Mazda Tribute";

        return car;
    }

    // define a private interface containing the setters.
    private interface ICarSetters
    {
        // define the setter in the private interface
        string model { set; }
    }

    // This is the inner class. It has a member "model" that should not be modified
    // but clients, but should be modified by the factory.
    public class Car: ICarSetters
    {
        // explicitly implement the setter
        string ICarSetters.model { set; }

        // create a public getter
        public string model { get; }
    }
}

class Client
{
    public Client()
    {
        Factory.Car car = Factory.CreateCar();

        // can only read model because only the getter is public
        // and ICarSetters is private to Factory
        string model = car.model;
    }
}

그것이 내가 명시 적 인터페이스를 사용하는 것입니다.


3

클래스가 동일한 서명을 가진 멤버를 포함하는 두 개의 인터페이스를 구현하는 경우 클래스에서 해당 멤버를 구현하면 두 인터페이스가 해당 멤버를 구현으로 사용하게됩니다. 다음 예제에서 모든 Paint호출은 동일한 메소드 를 호출합니다. 씨#

class Test 
{
    static void Main()

    {
        SampleClass sc = new SampleClass();
        IControl ctrl = (IControl)sc;
        ISurface srfc = (ISurface)sc;

        // The following lines all call the same method.
        sc.Paint();
        ctrl.Paint();
        srfc.Paint();
    }
}


interface IControl
{
    void Paint();
}
interface ISurface
{
    void Paint();
}
class SampleClass : IControl, ISurface
{
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint()
    {
        Console.WriteLine("Paint method in SampleClass");
    }
}

반대로, 이들 중 하나 (또는 ​​둘 다)를 명시 적으로 구현하면 각각에 대해 다른 동작을 지정할 수 있습니다.


1

명시 적 인터페이스는 개체에 둘 이상의 매우 다른 형태의 통신이있을 때 유용합니다.

예를 들어 부모와 통신해야하는 자식 개체 컬렉션을 유지 관리하는 개체입니다.

외부 발신자 만 액세스 할 수있는 작업과 하위 개체 만 액세스 할 수있는 작업이 있습니다.

명시 적 인터페이스는 이러한 구분을 보장합니다.

    static void Main(string[] args)
    {
        var parent = new Parent();
        parent.DoExternalStuff();
    }

    interface IExternal {
        void DoExternalStuff();
    }

    interface IInternal {
        void DoInternalStuff();
    }

    class Parent : IExternal, IInternal
    {
        public Parent()
        {
            var child = new Child(this);
        }

        public void DoExternalStuff()
        {
           // do something exciting here for external callers
        }

        void IInternal.DoInternalStuff()
        {
            // do something exciting here for internal callers
        }
    }

    class Child
    {
        public Child(IInternal parent)
        {
            parent.DoInternalStuff();
        }
    }

0

어쩌면 사용자에게 유용한 기능이 있지만 실제로 수행중인 작업을 알고있는 경우 (기능에 대해 배우기 위해 설명서를 충분히 읽어야 함) 만 그렇지 않으면 작동하지 않을 수 있습니다.

제공하지 않고 왜 그렇게 하겠는가, 내가 모르는 두 번째 "고급 기능 인터페이스"라고 말하십시오.


0

코드는 일반적으로 작성된 것보다 더 많이 읽으며 Intellisense 만 사용하여 코드를 빠르게 작성합니다. Intellisense를 더 좋게 만들기 위해 코드를 특정 방식으로 작성하지는 않습니다.

나는 특히 어떻게 보지 않는다

((Interface) object) .method ()는 object.method ()보다 더 읽기 쉽습니다.

특정 객체에 대해 많은 방법이 있다면 신 객체인지 여부에 의문을 가질 수 있으며 실제로 여러 개의 간단한 객체로 나눌 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.