Открыто / Закрыто для гибкого программного обеспечения - PullRequest
0 голосов
/ 06 мая 2011

Название может быть не слишком описательным, но я не мог придумать лучшего.Я прошу прощения за это.

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

Итак, я использую некоторые классы для описания логических операторов.Подумайте о чем-то вроде этого:

condition = new And(new Equals("x", 5),
                    new EqualsOrOver("y", 20));

Теперь все это прекрасно, но проблема возникает, когда я хочу использовать эту систему классов.Сейчас я создаю систему, в которой условие должно быть переведено в предложение SQL WHERE.

Я мог бы сделать это несколькими способами, но, похоже, ни один из них не придерживается принципа Open / Closed.Например, я мог бы Database класс разобрать условие и сделать его SQL.Проблема в том, что таким образом я не могу расширить свой Condition без необходимости менять свой Database, поэтому мы не следуем за Open / Closed.

Другой способ - который кажется логичнымздесь - это добавить функцию toSQL() к моим Condition с.Однако в этом случае я не могу поменять базу данных на ту, в которой (только для имени) используется XML, для которого не требуется условие в формате SQL.

Один из способов решения этой проблемыВ прошлом было использовать фабрику.Заводской метод в этом случае будет выглядеть примерно так:

turnIntoSQLCondtion(Condition c)
{
    if (c instanceof Equals)
    {
         return new SQLEquals(c);
    }
    else if (c instanceof EqualsOrOver)
    {
         return new SQLEqualsOrOver(c);
    }
    else if (c instanceof And)
    {
         return SQLAnd(c);
    }
}

Это не так уж и приятно, но это уменьшит нарушение Open / Closed.

Теперь вы можетеподкласс вашей базы данных просто отлично.Вам просто нужно будет создать подкласс для вашей фабрики, и вам нужно будет создать новую группу Condition классов, специфичных для вашего Database.Вы также можете использовать свою магию на классах Условий.Вы можете создавать новые Condition s, но вам также придется создавать классы-компаньоны для каждого Database.Наконец, вам придется изменить ваши фабрики.

Это самое маленькое нарушение, которое мы видели до сих пор, но мы все еще нарушаем Open / Closed.Но на самом деле, я бы предпочел не нарушать это вообще.Есть ли способ сделать это, полностью придерживаясь Open / Closed?

Ответы [ 3 ]

1 голос
/ 06 мая 2011

Это не так уж и приятно, но это уменьшит нарушение Open / Closed

На самом деле нет.Этот метод является нарушением OSP;)

Проблема не так сложна, как вы думаете.Просто создайте фабрику операторов SQL, в которой вы сопоставляете каждый класс Условий с классом условий SQL.

    public class SqlFactory
    {
        private Dictionary<Type, Delegate> _factoryMethods
            = new Dictionary<Type, Delegate>();

        public void Assign<T>(Func<T, ISqlCondition> factoryMethod)
            where T : ICondition
        {
            _factoryMethods.Add(typeof (T), factoryMethod);
        }

        public ISqlCondition Create<T>(T source) where T : ICondition
        {
            Delegate factory;
            if (!_factoryMethods.TryGetValue(source.GetType(), out factory))
                return null;

            return ((Func<T, ISqlCondition>) factory)(source);
        }
    }

Использование:

        SqlFactory factory = new SqlFactory();
        factory.Assign<And>(obj => new SqlAnd(obj.Value));

        var and = new And();
        var sqlAnd = factory.Create(and);
0 голосов
/ 09 апреля 2012

Protected Variations (PV) стремится разрешить изменения в одной зоне без необходимости изменения в другой. Отклонение (делегирование) - это то, что предложил @jgauffin, но оно защищает только одну сторону, как вы указали. Возможно, вы также можете использовать управляемый данными дизайн (например, файл свойств) для различных типов Storage, чтобы защитить изменения в этом направлении. Я думал о Hibernate и Data Mapper при чтении вашего вопроса.

0 голосов
/ 06 мая 2011

Мне интересно, было бы здесь полезно какое-то расширение с помощью шаблонов Decorator?

Вы бы хотели определить свои предикаты почти как своего рода DSL или список правил, которые могут быть проанализированы соответствующим образом.

Если вы декорируете ваш WherePredicate как SqlPredicate, то он прочитает этот набор правил и вернет оператор SQL;XmlPredicate будет делать то же самое.

Это оставит вас в хорошей открытой / закрытой ситуации. Открывать можно расширять, добавляя новый декоратор, и закрывать для модификации, так как список правил неприкосновенен.

...