理解开闭原则
当我遇到以下代码时,我正在重构简单脚本文件解析器的一些旧代码:
StringReader reader = new StringReader(scriptTextToProcess);
StringBuilder scope = new StringBuilder();
string line = reader.ReadLine();
while (line != null)
{
switch (line[0])
{
case '$':
// Process the entire "line" as a variable,
// i.e. add it to a collection of KeyValuePair.
AddToVariables(line);
break;
case '!':
// Depending of what comes after the '!' character,
// process the entire "scope" and/or the command in "line".
if (line == "!execute")
ExecuteScope(scope);
else if (line.StartsWith("!custom_command"))
RunCustomCommand(line, scope);
else if (line == "!single_line_directive")
ProcessDirective(line);
scope = new StringBuilder();
break;
default:
// No processing directive, i.e. add the "line"
// to the current scope.
scope.Append(line);
break;
}
line = reader.ReadLine();
}
在我看来,这个简单的脚本处理器是通过应用以下代码进行重构的良好候选者 : “开放封闭原则”。以 $
开头的行可能永远不会以不同的方式处理。但是,如果需要添加以 !
开头的新指令怎么办?或者需要新的处理标识符(例如新的开关盒)?
问题是,我不知道如何在不破坏 OCP 的情况下轻松、正确地添加更多指令和处理器。使用 scope
和/或 line
的 !
情况使得它有点棘手,也是如此默认情况。
有什么建议吗?
I was refactoring some old code of a simple script file parser when I came across the following code:
StringReader reader = new StringReader(scriptTextToProcess);
StringBuilder scope = new StringBuilder();
string line = reader.ReadLine();
while (line != null)
{
switch (line[0])
{
case '
This simple script processor seems to me like a good candidate for refactoring by applying the "open closed principle". The lines beginning with a $
will probably never be handled differently. But, what if new directives beginning with a !
needs to be added? Or new processing identifiers (e.g. new switch-cases) are needed?
The problem is, I could not figure out how to easily and correctly add more directives and processors without breaking OCP. The !
-case using scope
and/or line
makes it a bit tricky, as does the default
-case.
Any suggestions?
:
// Process the entire "line" as a variable,
// i.e. add it to a collection of KeyValuePair.
AddToVariables(line);
break;
case '!':
// Depending of what comes after the '!' character,
// process the entire "scope" and/or the command in "line".
if (line == "!execute")
ExecuteScope(scope);
else if (line.StartsWith("!custom_command"))
RunCustomCommand(line, scope);
else if (line == "!single_line_directive")
ProcessDirective(line);
scope = new StringBuilder();
break;
default:
// No processing directive, i.e. add the "line"
// to the current scope.
scope.Append(line);
break;
}
line = reader.ReadLine();
}
This simple script processor seems to me like a good candidate for refactoring by applying the "open closed principle". The lines beginning with a $
will probably never be handled differently. But, what if new directives beginning with a !
needs to be added? Or new processing identifiers (e.g. new switch-cases) are needed?
The problem is, I could not figure out how to easily and correctly add more directives and processors without breaking OCP. The !
-case using scope
and/or line
makes it a bit tricky, as does the default
-case.
Any suggestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用
Dictionary
指定应如何处理字符。如果字典中不存在字符键,则调用DefaultHandler
。添加一个
Add(char key, YourDelegate handler)
方法,允许任何人处理特定字符。更新
最好使用接口:
请注意,我传递的是
TextReader
。它提供了更大的灵活性,因为源可以是从简单字符串到复杂流的任何内容。更新 2
我也会以类似的方式分解
!
处理。即创建一个处理 IMyHandler 的类:这为处理实际协议和添加更多命令提供了更大的灵活性。您无需更改任何内容即可添加更多功能。因此,该解决方案在开放/封闭和其他一些 SOLID 原则方面是可以的。
Use a
Dictionary<Char, YourDelegate>
to specify how a character should be handled. CallDefaultHandler
if the character key do not exist in the dictionary.Add a
Add(char key, YourDelegate handler)
method allowing anyone to handle a specific character.Update
It's better to work with interfaces:
Note that I pass in a
TextReader
instead. It gives much more flexibility since the source can be anything from a simple string to a complex stream.Update 2
I would also break up the
!
handling in a similar way. i.e. Create a class that handles IMyHandler:That gives more flexibility for both handling the actual protocol and add more commands. you do not have to change anything to add more functionality. The solution is therefore OK regarding Open/Closed and some other SOLID principles.