代码之家  ›  专栏  ›  技术社区  ›  geejay

将资源注入抽象类

  •  1
  • geejay  · 技术社区  · 16 年前

    我有一个抽象类,形状,我有一个画布对象,形状用来设置它的位置。我需要确保所有形状都有一个画布对象,最好是一个在所有形状上都相同的画布对象。

    我想了几个选择:

    • 将画布参数添加到形状构造函数(有许多)

    • 在抽象形状得到画布的地方(当需要默认值时)

    • 让我所有的造型都经过某种工厂。

    哪一个最好?

    我用的是C/.NET 3.5

    4 回复  |  直到 16 年前
        1
  •  0
  •   Mark Seemann    16 年前

    对于依赖注入(DI)最好 违约 模式是 构造器注入 (第一个选项),因为它可以很容易地实现以确保形状的不变量。

    只需向形状ctor添加一个guard子句,如下所示:

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

    这样可以确保画布字段 总是 可用和 从未 无效的。

    您可以用其他方法实现这个属性,但是构造注入是迄今为止确保不变量的最简单方法,所以我总是选择它作为我的默认DI策略,除非我有其他需要。

        2
  •  0
  •   S M Kamran    16 年前

    你有没有想过另一个方向。我的意思是有一个画布对象,然后添加形状对象。这样,所有图形对象都有一个公共的参考点,即画布。有一组形状的画布对象。通过这种方式,可以对形状执行常见操作,例如在画布调整大小时调整所有形状的大小。

        3
  •  0
  •   grega g    16 年前

    拥有由DI框架注入的icanvas公共财产怎么样? 如果您真的有很多类实现shape,这意味着有很多带有canvas参数的构造函数,对于属性,您在shape中声明它一次,然后在任何地方使用它。

        4
  •  0
  •   vgru    16 年前

    我和S M Kamran有一个相似的想法:你可以 Canvas 您的财产 Shape 类以指示该形状所属的画布,以及 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);
    

    注意 ShapeCollection 是内部嵌套类 形状 因为这是唯一一种设置隐私的方法 _canvas 财产。

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

    您还可以创建一个“空/默认画布”单例,并在形状未分配给实际画布时使用它而不是空(只是为了避免检查 画布 每次都为空)。