Открытый Закрытый Принцип и Стратегия Вопрос Вопрос - PullRequest
1 голос
/ 19 декабря 2010

У меня есть пара идей, но я хотел посмотреть, что предложит сообщество SO.

У меня есть абстрактный класс с абстрактным методом Calculate.У меня есть 2 реализации этого, которые рассчитывают по-разному.Это кричащий шаблон Стратегии для меня, однако одна из реализаций требует, чтобы переменная selected_type была установлена, потому что она используется внутри метода Calculate.Я хочу следовать за OCP, поэтому мой метод Calculate не должен принимать зависимости.

Этот класс извлекается из БД через NHibernate, и переменная selected_type не будет установлена ​​до тех пор, пока объект не будет создан.Я пытаюсь избежать оператора if для установки selected_type, только если он имеет конкретную реализацию.Что будет лучшим способом?

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

public abstract class TagType
{
        public virtual long id { get; protected set; }
        public virtual string description { get; protected set; }

        protected TagType(){}

        protected TagType(string description)
        {
            this.description = description;
        }

        public abstract decimal Calculate();
}

public class TagTypeImpl1
{
    public virtual int tag_months { get; protected set; }

    protected TagType() { }

    protected TagType(string description, int tag_months): base(description)
    {
        this.tag_months = tag_months;
    }

    public override decimal Calculate()
    {
        return (12*tag_months);
    }
}

public class TagTypeImpl2
{
    public virtual int tag_months { get; protected set; }
    public virtual TagType selected_tag_type { get; protected set; }

    protected TagType() { }

    protected TagType(string description, int tag_months, TagType selected_tag_type): base(description)
    {
        this.tag_months = tag_months;
        this.selected_tag_type = selected_tag_type;
    }

    public override decimal Calculate()
    {
        return selected_tag_type.Calculate() + (12*tag_months);
    }
}

public class ConsumerController
{
    private readonly IRepository<TagType> repository;

    public ConsumerController(IRepository<TagType> repository)
    {
        this.repository = repository;
    }

    public ActionResult Index(long id)
    {
        var tag_type = repository.get(id);

        //If using TagTypeImpl2 then the selected_tag_type variable needs to be set
        //I want to avoid if(tag_type.GetType() == typeof(TagTypeImpl2)) set selected_tag_type
        var result = tag_type.Calculate();

        return Json(new {result});
    }
}

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

Ответы [ 2 ]

1 голос
/ 19 декабря 2010

Имеет ли смысл создавать виртуальную (переопределяемую) функцию «Initialize», которая должна вызывать все объекты tag_type, загруженные из репозитория, чтобы они могли делать то, что пропустил конструктор по умолчанию, как это сделал бы параметризованный конструктор? *

Или вы можете изменить конструктор по умолчанию, чтобы инициализировать selected_type либо правильным значением, либо некоторым значением, которое будет указывать методу вычисления исправлять его перед его использованием?

0 голосов
/ 21 декабря 2010

Ответственность за то, что нужно стратегии, лежит не на вашем классе, а на стратегии. Вся идея в том, что вы можете называть любую стратегию, которую используете, все время одинаково.

Просто заставьте все стратегии реализовывать один и тот же интерфейс - включая selected_type-, но одна из них игнорирует selected_type, а другая использует его. Это решает сама стратегия.

Кроме того, ваши реализации стратегии могут иметь больше свойств, чем определено в интерфейсе. Если вы можете инициализировать стратегии извне вашего класса, и для инициализирующего класса не является проблемой узнать больше о конкретной реализации, вы можете установить свойства только для конкретной стратегии, которая нуждается в ней. Хотя первое решение чище (всегда используется один и тот же интерфейс).

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