开放/封闭的灵活软件

发布于 2024-11-05 11:12:39 字数 1356 浏览 6 评论 0原文

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

因此,我现在遇到的问题是我已经遇到过几次的问题。它实际上是关于设计模式和原则的,并且是独立于语言的,只要您的语言具有面向对象的功能。我将带您解决我当前遇到的问题,因为如果没有实际的示例,很难解释问题是什么。

因此,我在这里使用一些类来描述逻辑语句。想像这样:

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

现在这一切都很漂亮,但是当我想使用这个类系统时问题就来了。现在,我正在创建一个系统,其中条件需要转换为 SQL WHERE 子句。

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

另一种方法 - 在这里看起来很合乎逻辑 - 是将一个 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);
    }
}

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

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

这是迄今为止我们见过的最小的违规行为,但我们仍然违反了开放/封闭规则。但事实上,我宁愿完全不违反它。有没有办法在始终坚持打开/关闭的情况下做到这一点?

The title may not be too descriptive, but I couldn't think of a better one. I'm sorry for that.

So, the problem I am having here is one I have come across a couple of times now. It's really about design patterns and principles, and is language independent as long as you have OO facilities in your language. I'll take you through the current problem I am having, as it is hard to explain what the problem is without an actual example.

So, I am using some classes to describe logic statements here. Think of something like this:

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

Now this is all dandy and all, but the problem comes when I want to use this class system. Right now, I am making a system where the condition needs to be translated to an SQL WHERE clause.

I could do this in several ways, but none seem to adhere to the Open/Closed principle. For example, I could have the Database class parse the condition and make it SQL. The problem is that in this way, I can't extend my Condition without the need to change my Database, thus we're not following Open/Closed.

Another way - which would seem logical here - is to add a toSQL() function to my Conditions. However, in that case, I am unable to swap my Database for one that (just to name something) uses XML, that doesn't want the condition in SQL format.

One way I have worked around this problem in the past has been to use a factory. The factory method in this case would look something like this:

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);
    }
}

This isn't all that nice, but it will reduce the violation of Open/Closed.

Now, you can subclass your Database just fine. You will just have to subclass your factory as well, and you will have to make a new bunch of Condition classes specific to your Database as well. You can also work your magic on the Condition classes as well. You can make a new Conditions, but you will have to make companion classes for each Database as well. Lastly, you will have to modify your factories.

It's the smallest violation we have seen so far, but we are still violating Open/Closed. But as a matter of fact, I would much rather not violate it at all. Is there a way to do this while sticking to Open/Closed all the way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

呆萌少年 2024-11-12 11:12:39

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

实际上没有。该方法违反了 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);

This isn't all that nice, but it will reduce the violation of Open/Closed

Actually no. That method is a violation of OSP ;)

The problem is not as hard as you might think. Simple create a SQL statement factory where you map each Condition class to a SQL condition class.

    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);
        }
    }

Usage:

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

        var and = new And();
        var sqlAnd = factory.Create(and);
夜唯美灬不弃 2024-11-12 11:12:39

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

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

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

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

I'm wondering if some extension by the Decorator patterns would be useful here ?

You'd want to define your predicates almost as a kind of DSL, or a list of rules that can be parsed appropriately.

If you decorate your WherePredicate as a SqlPredicate, then it would read this set of rules and return a SQL statement; an XmlPredicate would do similar.

That would leave you in a nice open/closed situation, Open to extend by adding a new decorator and closed for modification as you the list of rules is inviolable.

无声静候 2024-11-12 11:12:39

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

Protected Variations (PV) strives to allow variations in one zone without requiring modification in another. An indirection (delegation) is what @jgauffin proposed, but it only protects one side as you point out. Perhaps you can also use data-driven design (e.g., property file) for different Storage types to protect variations in that direction. I thought of Hibernate and Data Mapper when reading your question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文