开放/封闭的灵活软件
标题可能不太具有描述性,但我想不出更好的标题。我对此感到抱歉。
因此,我现在遇到的问题是我已经遇到过几次的问题。它实际上是关于设计模式和原则的,并且是独立于语言的,只要您的语言具有面向对象的功能。我将带您解决我当前遇到的问题,因为如果没有实际的示例,很难解释问题是什么。
因此,我在这里使用一些类来描述逻辑语句。想像这样:
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 Condition
s. 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 Condition
s, 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
实际上没有。该方法违反了 OSP ;)
问题并不像您想象的那么难。简单地创建一个 SQL 语句工厂,在其中将每个 Condition 类映射到 SQL 条件类。
用法:
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.
Usage:
我想知道装饰器模式的一些扩展在这里是否有用?
您希望将谓词定义为一种 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.
受保护的变体 (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.