了解开闭原则 [英] Understanding the Open Closed Principle

查看:149
本文介绍了了解开闭原则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的重构一个简单的脚本文件解析器当我碰到下面的代码来了一些旧代码:

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 '$':
            // 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?

现在的问题是,我无法弄清楚如何轻松地和正确地添加更多的指令和处理器不破OCP。在 - 案例使用范围 和/或 使得它有点棘手,一样的默认 - 案例。

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.

有什么建议?

推荐答案

使用词典<字符,YourDelegate> 来指定如何字符的处理方式。呼叫的DefaultHandler 如果该字符键没有在字典中。

Use a Dictionary<Char, YourDelegate> to specify how a character should be handled. Call DefaultHandler if the character key do not exist in the dictionary.

添加添加(字符键,YourDelegate处理器)法允许任何人来处理特定的字符。

Add a Add(char key, YourDelegate handler) method allowing anyone to handle a specific character.

这是更好地与接口的工作:

It's better to work with interfaces:

/// <summary>
/// Let anyone implement this interface.
/// </summary>
public interface IMyHandler
{
    void Process(IProcessContext context, string line);
}

/// <summary>
/// Context information
/// </summary>
public interface IProcessContext
{
}


// Actual parser
public class Parser
{
    private Dictionary<char, IMyHandler> _handlers = new Dictionary<char, IMyHandler>();
    private IMyHandler _defaultHandler;

    public void Add(char controlCharacter, IMyHandler handler)
    {
        _handlers.Add(controlCharacter, handler);
    }

    private void Parse(TextReader reader)
    {
        StringBuilder scope = new StringBuilder();
        IProcessContext context = null; // create your context here.

        string line = reader.ReadLine();
        while (line != null)
        {
            IMyHandler handler = null;
            if (!_handlers.TryGetValue(line[0], out handler))
                handler = _defaultHandler;

            handler.Process(context, line);


            line = reader.ReadLine();
        }
    }
}

请注意,我传递一个的TextReader 来代替。它给了更多的灵活性,因为源可以是从简单的字符串到复杂的流的任何

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.

我也打破了处理以类似的方式。即创建处理IMyHandler类:

I would also break up the ! handling in a similar way. i.e. Create a class that handles IMyHandler:

public interface ICommandHandler
{
    void Handle(ICommandContext context, string commandName, string[] arguments);
}

public class CommandService : IMyHandler
{
    public void Add(string commandName, ICommandHandler handler) 
    {
    }

    public void Handle(IProcessContext context, string line)
    {
       // first word on the line is the command, all other words are arguments.
       // split the string properly

       // then find the corrext command handler and invoke it.
       // take the result and add it to the `IProcessContext`
    }
}

这给出了两种处理实际协议,并添加更多命令更大的灵活性。你没有改变任何东西,以增加更多的功能。该解决方案是因此就OK开/关和其他一些固体原则。

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.

这篇关于了解开闭原则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆