如何在C#中处理组合类

时间:2017-08-23 15:05:43

标签: c# inheritance design-patterns interface composition

我所问的部分与设计模式有关。

假设我有一个 IDrawing 界面。 另外两个名为 TextDrawing ShapeDrawing 的基本类实现了这个,我有一个知道如何绘制这些类的View类!

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

如何在 查看 类中绘制这些内容?显然,教授 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!
           }
      }
   }

更新

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

3 个答案:

答案 0 :(得分: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();
    }
}

UPDATE - 摘要对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(...);
}

以及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 */ }
}

IDrawing界面更新为

public interface IDrawing
{
    void Draw(IDrawingContext drawingContext);
}

更新您的课程以反映此更改。您的类将调用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);
    }
}

答案 1 :(得分:4)

您可以选择强制类实现名为Draw()的方法。

public interface IDrawing
{
    void Draw(); 
}

现在你可以简单地调用这个方法,并将内部实现的责任交给自己。

public void Draw(IDrawing drawing)
{

     drawing.Draw();

例如,TextDrawing将被迫实施此方法

public class TextDrawing : IDrawing
{
    public void Draw()
    {
        // draw Text-like
    }
}

View课程中,对drawing.Draw();的调用将导致正确的实施。

  

如何告诉View的Draw方法知道复杂类的原始部分并绘制它们?

现在在复杂的类中,您只需使用已经在简单绘图类中实现的方法

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

    public void Draw()
    {
        Text.Draw();

        Border.Draw();

        Text.Draw();
    }
}

答案 2 :(得分:2)

you can polymorphically draw without checking the type.

 public class View
   {
      public void Draw(IDrawing drawing)
      {
         drawing.Draw();
      }
   }
Encapsulate each drawing strategy (Strategy Pattern) in different class and you could inject each strategy via DI.