문제

나는 몇 가지 논리,정의와 사용하는 일부 사용자 정의 형식은 이들을 좋아한다:

class Word
{
  System.Drawing.Font font; //a System type
  string text;
}

class Canvass
{
  System.Drawing.Graphics graphics; //another, related System type
  ... and other data members ...
  //a method whose implementation combines the two System types
  internal void draw(Word word, Point point)
  {
    //make the System API call
    graphics.DrawString(word.text, word.font, Brushes.Block, point);
  }
}

로직을 수행 한 후,계산이 유형(예를들면서로를 찾는 Word 인스턴스),간접적으로 사용 System APIs,예를 들어를 호출하여 Canvass.draw 방법입니다.

나는 다음과 같이 논의 독립 System.Drawing 네임스페이스:대부분을 돕기 위해,단위 테스트(나는 생각한 단위 테스트를 출력하는 것이 더 쉽지 확인하는 경우 draw 방법 그리기가 아닌 다른 부 System.Drawing.Graphics 인스턴스).

을 제거하고 논리의 속국에서 System.Drawing 네임스페이스,나는 선언하는 몇 가지 새로운 인터페이스의 자리 표시자로 System.Drawing 유형,예를 들어:

interface IMyFont
{
}

interface IMyGraphics
{
  void drawString(string text, IMyFont font, Point point);
}

class Word
{
  IMyFont font; //no longer depends on System.Drawing.Font
  string text;
}

class Canvass
{
  IMyGraphics graphics;  //no longer depends on System.Drawing.Graphics
  ... and other data ...

  internal void draw(Word word, Point point)
  {
    //use interface method instead of making a direct System API call
    graphics.drawText(word.text, word.font, point);
  }
}

는 경우 내가 이것 다음,다른 어셈블리할 수 있는 다른 구현 IMyFontIMyGraphics 인터페이스 예를 들어,...

class MyFont : IMyFont
{
  System.Drawing.Font theFont;
}

class MyGraphics : IMyGraphics
{
  System.Drawing.Graphics theGraphics;

  public void drawString(string text, IMyFont font, Point point)
  {

    //!!! downcast !!!

    System.Drawing.Font theFont = ((MyFont)font).theFont;

    //make the System API call
    theGraphics.DrawString(word.text, theFont, Brushes.Block, point);
  }
}

...그러나 이 구현에 필요한 낙심과 같이다.

나의 질문은, 이 있을 할 수 있는 방법 이 필요로하지 않고 낙심에서 구현? 에 의해"이"나는 말은"정의는 다음과 같 Udt WordCanvass 는지에 따라 특정 콘크리트 System 형식"은?

는 대안이 될 것 이라고 추상적인 Udt...

class Word
{
  //System.Drawing.Font font; //declared in a subclass of Word
  string text;
}

class Canvass
{
  //System.Drawing.Graphics graphics; //declared in a subclass of Canvass
  //concrete draw method is defined in a subclass of Canvass
  internal abstract void draw(Word word, Point point); 
}

...하지만 이것은 너무 필요 낙심에서의 구현은 서브 클래스.

또한 나의 생각을 사용하여 더블 dispatch 관용구,하지만 그에 따라 이름 지정이 다양한 서브 클래스에서 일으킬 수 있습니다.

거나,하지 않을 경우 인터페이스 또는 하위 클래스가 어떤 방법을 사용하여 대리인?


--편집:-

이 있었다 가능한 두 개의 답변이 있습니다.

하나 응답이 제네릭을 사용하기 위해,정확하게로에 의해 제안된'선생님 란티스'답변을 아래와 같이 제 블로그 글을 존 스키트 연결되어 있습니다.생각이 잘 작동에서 대부분의 시나리오.아래쪽 나의 관점에서 다는 것을 의미한 소개 TFont 템플릿으로 매개변수:그것은뿐만 아니라 다음과 같이 클래스 Word (을 포함하는 Font 인스턴스)는 요구되는 일반적인 클래스(아 WordT<TFont>)...그것은 또한 모든 등을 포함하는 WordT<TFont> (예: Paragraph 이)이제 필요가 일반으로 TFont 매개 변수(예를들면 ParagraphT<TFont>).결국,거의 모든 클래스에서는 어셈블리가 일반적인 클래스입니다.이 유형-안전 및 피해야 downcast... 그것의 종류의 추악,그리고 방해 환상의 캡슐에 넣기(는 환상'폰트'는 불투명한 세부 구현).

또 다른 대답을 사용하는 것도 또는 사전에 사용자는 클래스입니다.대 Font 에서 재사용할 수 있는 라이브러리 대신,추상 인터페이스를 정의한'처'등 다음과 같:

public struct FontHandle
{
  public readonly int handleValue;
  FontHandle(int handleValue)
  {
    this.handleValue = handleValue;
  }
}

그런 다음 대신에서 downcasting FontHandle, 지 Dictionary<int, Font> 인스턴스는 지도 FontHandleFont 인스턴스가 있습니다.

도움이 되었습니까?

해결책

첫째, 전체 시나리오가 약간 인공적이지 않은지 궁금합니다. 당신은 정말로 가고 있습니까? 필요 이 추상화 수준? 아마도 구독 할 것입니다 야그니?

왜 당신의 MyGraphics a MyFont? AN과 함께 작동 할 수 있습니다 IFont? 그것은 인터페이스를 더 잘 활용 하고이 전체 문제를 피할 것입니다 ...

하나의 옵션은 약간의 재 설계 일 수 있으므로 IFont 글꼴의 메타 데이터 (크기, 글꼴 팬 스페이스 등)를 설명하면 콘크리트에 물건이 있습니다. MyGraphics 처럼:

[public|internal] MyFont GetFont(IFont font) {...} // or just Font

그리고 번역을하는 것은 그래픽의 작업이됩니다. 따라서 다음과 같은 것을 사용했습니다.

public void drawString(string text, IMyFont font, Point point)
{
    using(System.Drawing.Font theFont = GetFont(font))
    {
        theGraphics.DrawString(word.text, theFont, Brushes.Block, point);
    }
    // etc
}

물론, Point 번역이 필요할 수 있습니다; -p

다른 팁

당신은 효과적으로 "컴파일러보다 더 잘 알고 있습니다 - 나는 그것이 인스턴스가 될 것임을 알고 있습니다. MyFont. "그 시점에서 당신은 가지고 있습니다 MyFont 그리고 MyGraphics 다시 단단히 결합되어 인터페이스의 점이 약간 줄어 듭니다.

해야 한다 MyGraphics 어떤 것과 함께 일하십시오 IFont, 또는 a MyFont? 당신이 그것을 만들 수 있다면 IFont 너는 괜찮아 질거다. 그렇지 않으면 복잡한 제네릭을보고 모든 컴파일 타임 유형을 안전하게 만들어야 할 수도 있습니다. 당신은 찾을 수 있습니다 프로토콜 버퍼의 제네릭에 대한 내 게시물 비슷한 상황으로 유용합니다.

(측면 제안 - 방법에 대한 파스칼 사례를 포함하는 이름 지정 규칙을 따르는 경우 코드가 더 특이 적으로 .NET -like입니다.)

나는 현재 C#을 더 이상 잘 모르고 있습니다. 지금은 시간이 지났습니다. 그러나 모든 물건을 거기에 캐스팅하고 싶지 않다면 제네릭을 사용해야 할 수도 있습니다.

Java 코드를 제공 할 수 있지만 C#은 where 예어.

인터페이스를 일반 인터페이스로 만드십시오. 자바에서

IMyGraphics<T extends IMyFont>그리고 MyGraphics : IMyGraphics<MyFont>

그런 다음 재정의하십시오 drawString 취할 서명 T font 대신 두 번째 매개 변수로 IMyFont. 이것은 당신이 쓸 수있게해야합니다

public void drawString(string text, MyFont font, Point point)

당신의 직접 MyGraphics 수업.


C#에서 IMyGraphics<T extends IMyFont> 해야한다 public interface IMyGraphics<T> where T:IMyFont, 그러나 나는 그것에 대해 100% 확실하지 않습니다.

지에서 캐스팅 IFont 하기 MyFont?당신이 작업을 수행 할 수 있습니다:

interface IFont {
    object Font { get; }
}

class MyFont : IFont {
    object Font { get { return ...; } }
}

물론 당신은 여전히 해야에서 캐스팅 System.Object 하기 System.Drawing.Font 에서 드로잉 방법,그러나 당신은 단지 제거에 대한 의존도는 특정 클래스 구현(MyFont).

public void DrawString(string text, IFont font, Point point)
{
    System.Drawing.Font f = (Font)font.Font;
    graphics.DrawString(text, f, Brushes.Block, point);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top