0

标题可能不太具有描述性,但我想不出更好的标题。我很抱歉。

所以,我在这里遇到的问题是我现在遇到过几次的问题。它实际上与设计模式和原则有关,只要您的语言中有 OO 工具,它就与语言无关。我将带您了解当前遇到的问题,因为如果没有实际示例,很难解释问题所在。

所以,我在这里使用一些类来描述逻辑语句。想想这样的事情:

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

现在这一切都是花花公子,但是当我想使用这个类系统时问题就来了。现在,我正在制作一个需要将条件转换为 SQL WHERE 子句的系统。

我可以通过多种方式做到这一点,但似乎都没有遵守开放/封闭原则。例如,我可以让Database类解析条件并将其设为 SQL。问题是,通过这种方式,我无法Condition在不需要更改 my 的情况下扩展 my Database,因此我们没有遵循 Open/Closed。

另一种方法——在这里看起来很合乎逻辑——是在toSQL()my s.s 中添加一个函数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);
    }
}

这不是那么好,但它会减少对打开/关闭的违反。

现在,您可以很好地继承您的数据库。你也只需要对你的工厂进行子类化,并且你还必须为你的工厂创建一堆新的ConditionDatabase。你也可以在 Condition 类上发挥你的魔力。您可以创建一个新Condition的 s,但您也必须为每个创建伴随类Database。最后,您将不得不修改您的工厂。

这是迄今为止我们看到的最小的违规行为,但我们仍然违反了 Open/Closed。但事实上,我宁愿完全不违反它。有没有办法在坚持打开/关闭的同时做到这一点?

4

3 回答 3

1

这不是那么好,但它会减少对 Open/Closed 的违反

其实没有。该方法违反了 OSP ;)

这个问题并不像你想象的那么难。简单地创建一个 SQL 语句工厂,在其中将每个 Condition 类映射到一个 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);
于 2011-05-06T12:27:15.430 回答
0

我想知道装饰器模式的一些扩展在这里是否有用?

您可能希望将谓词定义为一种 DSL,或者可以适当解析的规则列表。

如果您将 WherePredicate 装饰为 SqlPredicate,那么它将读取这组规则并返回一条 SQL 语句;XmlPredicate 会做类似的事情。

这将使您处于一个很好的打开/关闭状态,通过添加新的装饰器来扩展并关闭以进行修改,因为您的规则列表是不可侵犯的。

于 2011-05-06T12:15:17.143 回答
0

受保护的变化 (PV)力求在一个区域中允许变化,而无需在另一个区域中进行修改。间接(委托)是@jgauffin 提出的,但它只保护你指出的一侧。也许您还可以针对不同Storage类型使用数据驱动设计(例如,属性文件)来保护该方向的变化。阅读您的问题时,我想到了 Hibernate 和Data Mapper 。

于 2012-04-09T04:48:04.493 回答