Шаблон декоратора тратит память

У меня есть этот базовый класс со следующим интерфейсом:

abstract class Base
{
  abstract public object Val
  {
    get;
  }
}

Для любых производных классов значение Val должно указываться во время создания объекта.
Вопрос в следующем: как я могу заставить производный класс делать это (надеюсь, во время компиляции )?
Я попытался добавить конструктор:

abstract class Base
{
  public Base(object value)
  {
    val = value;
  }

  private object val;

  ...
}

Но, как видите, мне пришлось объявить приватное поле для хранения в нем значения (поскольку Value доступно только для чтения).
Проблема возникает из-за того, что я хочу добавить какой-то эффект к производным классам с помощью Decorator/Wrapper. шаблон, представленный в GoF Design Patterns. Но поскольку я объявил поле внутри базового класса, декораторы продолжают сохранять копию одних и тех же данных, и в итоге я теряю память.


person atoMerz    schedule 11.12.2011    source источник
comment
Декоратор — это объект, содержащий другой объект, поэтому вам, очевидно, нужна память для двух объектов. Именно столько памяти требуется для вашего решения. Если вас это не устраивает, возможно, вы неправильно используете или неправильно понимаете шаблон декоратора. Какую именно проблему вы хотите решить?   -  person Achim    schedule 11.12.2011
comment
Если я определяю только свойства (а не поля) в своем базовом классе, тогда декоратору фактически не придется хранить какие-либо другие копии базовых членов.   -  person atoMerz    schedule 11.12.2011
comment
Декоратор не хранит копии базовых элементов. Он просто хранит ссылку на украшенный объект!?   -  person Achim    schedule 11.12.2011
comment
Он также должен наследоваться от базового класса, чтобы иметь тот же интерфейс. Или я ошибаюсь?   -  person atoMerz    schedule 12.12.2011
comment
Вашему приложению когда-либо действительно не хватало памяти? Многим приложениям не нужно беспокоиться об оптимизации для этого.   -  person TrueWill    schedule 24.12.2011
comment
@TrueWill, нет, но это все равно имеет значение. Я знаю об этом и ненавижу хранить ненужные копии данных.   -  person atoMerz    schedule 25.12.2011
comment
Это отсылка. Думай указатель. Если вы не работаете с серьезными ограничениями памяти, не беспокойтесь об этом. Ваше время стоит больше.   -  person TrueWill    schedule 26.12.2011
comment
@TrueWill, это правда. Но я думаю, стоит научиться делать все правильно. Если бы это была задача, данная мне, я бы, вероятно, оставил ее в покое и занялся более важными вещами, но, поскольку я все еще учусь, я думаю, что должен убедиться, что делаю это правильно.   -  person atoMerz    schedule 26.12.2011


Ответы (2)


Попробуйте это вместо этого:

abstract class Base 
{
    public Base(object val)
    {
        this.Val = val;
    }

    public object Val { get; private set; }
}

Таким образом, вашему производному классу не нужно собственное поле:

public class Derived : Base
{
    public Derived(object val) : base(val) { }
}
person Jacob    schedule 11.12.2011
comment
@AtoMerZ обратите внимание, что у него все еще есть поле в базовом классе; просто - компилятор скрывает это от нас. Автоматически реализованные свойства имеют резервное поле, созданное компилятором. - person Marc Gravell; 11.12.2011

Если это декоратор, то не имеет поля:

public override object Val {
    // add any decoration effects here if needed
    get { return tail.Val; }
}

Где tail — это то, что вы украшаете.


Однако похоже, что вы имеете в виду наследование (а не украшение) - если это так:

abstract class BaseClass {
    protected BaseClass(object val) {...}
}
class ConcreteType : BaseClass {
    public ConcreteType(object val)
        : base(val) { }
}

Здесь базовый класс может даже обрабатывать хранилище и т. д.

person Marc Gravell    schedule 11.12.2011
comment
Может быть, я не совсем понимаю. Базовый класс имеет поле, и, поскольку декоратор наследует базовый класс, декоратор тоже. Я могу переопределить свойство Val, но это поле останется в памяти. - person atoMerz; 11.12.2011
comment
@AtoMerZ Я в замешательстве ... если вы не хотите, чтобы в базе было поле, тогда не имейте поля ... пусть производный класс беспокоится об этом. Если в базе нет поля, ему также не нужен конструктор - просто есть public abstract object Value {get;} и все готово... - person Marc Gravell; 11.12.2011
comment
Как я сказал в вопросе, производные классы ДОЛЖНЫ инициализировать val. Поэтому мне пришлось предоставить базовому классу конструктор для инициализации val. И это означало, что мне нужно было выделить память для свойства (поскольку я забыл о частном наборе, который был решением). - person atoMerz; 12.12.2011
comment
Кажется, вы путаете декоратор с прокси - person Ivo; 24.12.2011
comment
@ivowiblo нет, не думаю. Декоратор является шаблоном обтекания объектов. С чего ты взял, что я перепутал? - person Marc Gravell; 24.12.2011
comment
Mhhh... после дальнейшего чтения я ошибся. Одним из решений вашей проблемы будет заставить ваши декораторы реализовать общий интерфейс с вашими классами, но не расширять сам класс. Или поместите всю логику, связанную с этим полем, в другое дерево-декоратор. - person Ivo; 24.12.2011