繁体   English   中英

将资源注入抽象类

[英]Injecting a resource into an abstract class

我有一个抽象类Shape,并且我有一个Shape用来设置其位置的Canvas对象。 我需要确保所有Shapes都有一个Canvas对象,最好是一个在所有形状中都相同的Canvas对象。

我想到了几个选择:

  • 将画布参数添加到Shape构造函数中(有很多)

  • 在某种程度上可以使抽象Shape获得其Canvas(需要默认值时)

  • 使我所有的形状构造都要经过某种工厂。

哪一个是最好的?

我正在使用C#/ .NET 3.5

拥有由di框架注入的ICanvas公共财产怎么办? 如果确实有很多实现Shape的类,则意味着有很多具有Canvas参数的构造函数,对于属性,您可以在Shape中声明一次并在各处使用它。

您是否想过另一种方式。 我的意思是拥有一个画布对象,然后向其添加形状对象。 这样,您所有的形状对象都有一个共同的参考点,即Canvas。 具有形状集合的画布对象。通过这种方式,您可以执行常见的形状操作,例如在调整画布大小时调整所有形状的大小。

对于依赖注入(DI),最好的默认模式是构造函数注入 (首选),因为它可以轻松实现以确保Shape的不变性。

只需向您的Shape ctor添加一个Guard子句,如下所示:

private readonly Canvas canvas;

protected Shape(Canvas canvas)
{
    if(canvas == null)
    {
        throw new ArgumentNullException("canvas");
    }
    this.canvas = canvas;
}

这样可以确保canvas字段始终可用,并且永远不会为 null。

您可以通过其他方式实现此属性,但是到目前为止,Constructo Injection是确保不变性的最简单方法,因此,除非我有其他需求,否则我始终选择将其作为默认的DI策略。

我和SM Kamran有类似的想法:您可以在Shape类中具有Canvas属性,以指示该形状所属的画布,并在Canvas类中具有Shapes集合,以保存形状的集合:

这是一个简单的示例:

interface ICanvas
{
    // It's a good thing to use an interface
    // in this phase. It will allow you greater
    // freedom later.
}

class Canvas : ICanvas
{
    private Shape.ShapeCollection _shapes;
    public Collection<Shape> Shapes
    {
        get { return _shapes; }
    }

    public Canvas()
    {
        _shapes = new Shape.ShapeCollection(this);
    }
}

class Shape
{
    public class ShapeCollection : Collection<Shape>
    {
        private readonly ICanvas _parent;
        public ShapeCollection(ICanvas parent)
        {
            _parent = parent;
        }

        protected override void InsertItem(int index, Shape item)
        {
            item._canvas = _parent;
            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            this[index]._canvas = null;
            base.RemoveItem(index);
        }

        protected override void SetItem(int index, Shape item)
        {
            RemoveAt(index);
            InsertItem(index, item);
        }

        protected override void ClearItems()
        {
            while (this.Count != 0)
                this.RemoveAt(this.Count - 1);
        }
    }

    private ICanvas _canvas;
    public ICanvas Canvas
    {
        get { return _canvas; }
    }
}

通过向画布添加形状, Shape.Canvas属性将自动更新:

Canvas canvas = new Canvas();
Shape circle = new Shape();

canvas.Shapes.Add(circle);

请注意, ShapeCollectionShape内的嵌套类,因为它是设置私有_canvas属性的唯一方法。

通用集合(例如Collection<Shape> )通常用于类似的问题,因为在更改集合时,您可以覆盖它们的InsertItem / RemoveItem属性以添加自定义功能。

您还可以创建一个“空/默认画布”单例,并在未将形状分配给实际画布时使用它代替null(只是避免每次检查Shape.Canvas是否为null)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM