如何在C#中处理组合类

Vah*_*hid 5 c# inheritance design-patterns interface composition

我要问的是部分与设计模式有关.

可以说我有一个IDrawing界面.另外两个名为TextDrawingShapeDrawing的基本类实现了这个,我有一个知道如何绘制这些类的View类!

但是我有更复杂的绘图类,它们也实现了IDrawing接口,但它们本身由几个IDrawing类组成!

如何在我的View类中绘制这些?显然教会View类来绘制每个新的IDrawing并不是一个好主意!但我还有其他选择吗?也许设计不正确?如何告诉View的Draw方法知道复杂类的原始部分并绘制它们?

   public interface IDrawing
   {
   }

   public class TextDrawing : IDrawing
   {
   }

   public class ShapeDrawing : IDrawing
   {      
   }

   public class SignDrawing : IDrawing
   {
      public TextDrawing Text { get; set; }
      public ShapeDrawing Border { get; set; }
   }

   public class MoreComplexDrawing : IDrawing
   {
      public TextDrawing Text { get; set; }
      public ShapeDrawing Border1 { get; set; }
      public ShapeDrawing Border2 { get; set; }
   }

   public class View
   {
      public void Draw(IDrawing drawing)
      {
           // The View only knows how to draw TextDrawing and ShapeDrawing.
           // These as the primitive building blocks of all drawings.
           // How can it draw the more complex ones!
           if (drawing is TextDrawing)
           {
              // draw it
           }
           else if (drawing is ShapeDrawing)
           {
              // draw it
           }
           else
           {
              // extract the drawings primitive parts (TextDrawing and ShapeDrawing) and draw them!
           }
      }
   }
Run Code Online (Sandbox Code Playgroud)

更新:

我收到了在绘图类中实现Draw()方法的建议.View中的Draw方法依赖于要绘制的外部库(在我的例子中,它是SkiaSharp库).如果我在这些类中实现Draw,它们将不再是通用的!例如,我将无法在其他项目中使用它们,因为我有不同的策略来绘制东西.

phu*_*uzi 5

我会Draw()在接口中添加一个方法,并在每个类中实现它.

这样做的好处是你View不关心实际类型是什么.

public interface IDrawing
{
    void Draw();
}

public class TextDrawing : IDrawing
{
    public void Draw()
    {
        // Draw a TextDrawing
    }
}

public class ShapeDrawing : IDrawing
{      
    public void Draw()
    {
        // Draw a ShapeDrawing
    }
}

public class SignDrawing : IDrawing
{
    public TextDrawing Text { get; set; }
    public ShapeDrawing Border { get; set; }

    public void Draw()
    {
        // Draw a SignDrawing
    }
}

public class MoreComplexDrawing : IDrawing
{
    public TextDrawing Text { get; set; }
    public ShapeDrawing Border1 { get; set; }
    public ShapeDrawing Border2 { get; set; }

    public void Draw()
    {
        // Draw a MoreComplexDrawing
    }
}

public class View
{
    public void Draw(IDrawing drawing)
    {
        //Draw the drawing
        drawing.Draw();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新 - 摘要对SkiaSharp的依赖

您需要为SkiaSharp实际执行绘制的外部依赖项创建包装器.这应该与IDrawing接口和派生类存在于同一个程序集中.

public interface IDrawingContext
{
    // Lots of drawing methods that will facilitate the drawing of your `IDrawing`s
    void DrawText(...);
    void DrawShape(...);
    void DrawBorder(...);
}
Run Code Online (Sandbox Code Playgroud)

以及SkiaSharp具体实施

public class SkiaSharpDrawingContext IDrawingContext
{
    // Lots of drawing methods that will facilitate the drawing of your IDrawings
    public void DrawText(...) { /* Drawing code here */ }
    public void DrawShape(...) { /* Drawing code here */ }
    public void DrawBorder(...) { /* Drawing code here */ }
}
Run Code Online (Sandbox Code Playgroud)

IDrawing界面更新为

public interface IDrawing
{
    void Draw(IDrawingContext drawingContext);
}
Run Code Online (Sandbox Code Playgroud)

更新您的课程以反映此更改.您的类将调用IDrawingContext实现上的方法来进行绘制.

在应用程序中创建特定于依赖项的实现,并更新您的View类以使用新的SkiaSharpDrawingContext

public class View
{
    public void Draw(IDrawing drawing)
    {
        // This should ideally be injected using an IOC framework
        var drawingContext = new SkiaSharpDrawingContext(...);

        //Draw the drawing
        drawing.Draw(drawingContext);
    }
}
Run Code Online (Sandbox Code Playgroud)