Внедрение ресурса в абстрактный класс - PullRequest
1 голос
/ 05 октября 2009

У меня есть абстрактный класс Shape, и у меня есть объект Canvas, который Shape использует для установки своей позиции. Мне нужно убедиться, что у всех фигур есть объект Canvas, предпочтительно объект Canvas, который одинаков для всех фигур.

Я подумал о нескольких вариантах:

  • Добавление параметра холста в конструкторы Shape (их много)

  • Наличие какого-то места, где абстрактная форма получает свой холст (когда требуется значение по умолчанию)

  • Заставь всю мою конструкцию фигуры пройти через какую-нибудь фабрику.

Какой из них лучший?

Я использую C # / .NET 3.5

Ответы [ 4 ]

0 голосов
/ 05 октября 2009

У меня была идея, аналогичная SM Kamran: у вас может быть свойство Canvas в вашем классе Shape, чтобы указать холст, к которому принадлежит эта фигура, и коллекция Shapes в вашем классе Canvas для провести коллекцию фигур:

Вот краткий пример:

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 - это вложенный класс внутри Shape, потому что это единственный способ установить личное свойство _canvas.

Универсальные коллекции (например, Collection<Shape>) часто используются для схожих проблем, поскольку вы можете переопределить их свойства InsertItem / RemoveItem, чтобы добавить пользовательские функции при изменении коллекции.

Вы также можете создать синглтон «Пустой / Стандартный холст» и использовать его вместо нуля, когда фигуре не назначен реальный холст (просто чтобы не проверять, является ли Shape.Canvas нулевым каждый раз).

0 голосов
/ 05 октября 2009

Думал ли ты наоборот. Я имею в виду наличие объекта canvas и добавление к нему объекта фигур. Таким образом, все ваши объекты фигур имеют общую опорную точку - холст. Объект холста, имеющий коллекцию фигур. Таким образом, вы можете выполнять обычные операции с фигурами, например изменять размеры всех фигур при изменении размера холста.

0 голосов
/ 05 октября 2009

Для Dependency Injection (DI) лучший по умолчанию шаблон - Constructor Injection (ваш первый вариант), потому что его легко реализовать для обеспечения инвариантов ваших фигур.

Просто добавьте пункт «Охранник» к вашему кору «Форма» следующим образом:

private readonly Canvas canvas;

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

Это гарантирует, что поле canvas будет всегда доступно и никогда null.

Вы можете получить это свойство другими способами, но Constructo Injection, безусловно, является самым простым способом обеспечения инвариантов, поэтому я всегда выбираю его в качестве своей стратегии DI по умолчанию, если у меня нет других потребностей.

0 голосов
/ 05 октября 2009

А как насчет того, чтобы публичная собственность ICanvas была введена di framework? Если у вас действительно есть много классов, реализующих Shape, это означает, что у вас много конструкторов с параметром Canvas, для свойства вы объявляете его один раз в Shape и используете его везде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...