我怎么能将它重构为更易于管理的代码?

时间:2010-04-16 09:02:29

标签: c# json refactoring parsing

这段代码是否足够复杂,值得更高级别的抽象?

public static JsonStructure Parse(string jsonText)
{
    var result = default(JsonStructure);
    var structureStack = new Stack<JsonStructure>();
    var keyStack = new Stack<string>();
    var current = default(JsonStructure);
    var currentState = ParserState.Begin;
    var key = default(string);
    var value = default(object);

    foreach (var token in Lexer.Tokenize(jsonText))
    {
        switch (currentState)
        {
            case ParserState.Begin:
                switch (token.Type)
                {
                    case TokenType.BeginObject:
                        currentState = ParserState.Name;
                        current = result = new JsonObject();
                        break;
                    case TokenType.BeginArray:
                        currentState = ParserState.Value;
                        current = result = new JsonArray();
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.Name:
                switch (token.Type)
                {
                    case TokenType.String:
                        currentState = ParserState.NameSeparator;
                        key = (string)token.Value;
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.NameSeparator:
                switch (token.Type)
                {
                    case TokenType.NameSeparator:
                        currentState = ParserState.Value;
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.Value:
                switch (token.Type)
                {
                    case TokenType.Number:
                    case TokenType.String:
                    case TokenType.True:
                    case TokenType.False:
                    case TokenType.Null:
                        currentState = ParserState.ValueSeparator;
                        value = token.Value;
                        break;
                    case TokenType.BeginObject:
                        structureStack.Push(current);
                        keyStack.Push(key);
                        currentState = ParserState.Name;
                        current = new JsonObject();
                        break;
                    case TokenType.BeginArray:
                        structureStack.Push(current);
                        currentState = ParserState.Value;
                        current = new JsonArray();
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.ValueSeparator:
                var jsonObject = (current as JsonObject);
                var jsonArray = (current as JsonArray);
                if (jsonObject != null)
                {
                    jsonObject.Add(key, value);
                    currentState = ParserState.Name;
                }
                if (jsonArray != null)
                {
                    jsonArray.Add(value);
                    currentState = ParserState.Value;
                }
                switch (token.Type)
                {
                    case TokenType.EndObject:
                    case TokenType.EndArray:
                        currentState = ParserState.End;
                        break;
                    case TokenType.ValueSeparator:
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.End:
                switch (token.Type)
                {
                    case TokenType.EndObject:
                    case TokenType.EndArray:
                    case TokenType.ValueSeparator:
                        var previous = structureStack.Pop();
                        var previousJsonObject = (previous as JsonObject);
                        var previousJsonArray = (previous as JsonArray);
                        if (previousJsonObject != null)
                        {
                            previousJsonObject.Add(keyStack.Pop(), current);
                            currentState = ParserState.Name;
                        }
                        if (previousJsonArray != null)
                        {
                            previousJsonArray.Add(current);
                            currentState = ParserState.Value;
                        }
                        if (token.Type != TokenType.ValueSeparator)
                        {
                            currentState = ParserState.End;
                        }
                        current = previous;
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            default:
                break;
        }
    }
    return result;
}

2 个答案:

答案 0 :(得分:10)

在没有详细查看的情况下,当您基于状态进行解析时,是否可以使用state pattern将其拆分并根据状态解析单独类中的每个位?

这样的事情可能是一个开始,虽然这只是伪代码......

public interface IParserState
    {
    IParserState ParseToken (IToken token);
    }

public class BeginState : IParserState
    {
    private readonly Stack<JsonStructure> m_structureStack;
    private readonly Stack<String> m_keyStack;

    public BeginState (Stack<JsonStructure> structureStack, Stack<String> keyStack)
        {
        m_structureStack = structureStack;
        m_keyStack = keyStack;
        }

    public IParserState ParseToken(IToken token)
        {
        switch (token.Type)
            {
            case TokenType.OpenBrace:
                return new ObjectKeyParserState(m_structureStack,m_keyStack);
            case TokenType.OpenBracket:
                return new ArrayValueParserState(m_structureStack, m_keyStack);
            default:
                throw new JsonException (token);    
            }
        }
    }

public class ObjectKeyParserState : IParserState
    {
    private readonly Stack<JsonStructure> m_structureStack;
    private readonly Stack<String> m_keyStack;
    private readonly JsonObject m_current;

    public ObjectKeyParserState (Stack<JsonStructure> structureStack, Stack<String> keyStack)
        {
        m_current = new JsonObject();
        }

    public IParserState ParseToken (IToken token)
        {
        switch (token.Type)
            {
            case TokenType.StringLiteral:
                key = (string)token.Value;
                return new ColonSeperatorParserState(m_structureStack, m_keyStack, m_current,key);
            default:
                throw new JsonException(token);
            }
        }

答案 1 :(得分:2)

在这种情况下,“概念设计”是生产规则。如果你自己设计json,你会想到“一对是一个关键后跟一个冒号然后是一个值”或者你会想像“Colons会做'a'在这种情况下'A'和在'B'的情况下做'b',在'C'的情况下做'c'“?看看http://www.json.org/。您将看到根据生产规则陈述的“概念设计”。

由于代码的“结构设计”不具有“概念设计”的形式,因此任何重构都不会有所帮助。稍微改变“概念设计”会导致难以编码且难以测试的代码更改。您需要根据“概念设计”重写代码。

// object
//   "{" "}"
//   "{" members "}" 
private static JsonObject ProduceJsonObject(Tokens tokens)
{
    var result = new JsonObject();

    tokens.Accept( TokenType.OpenBrace );
    result.members = ProduceJsonMembers(tokens);
    tokens.Accept( TokenType.CloseBrace );

    return result;
}

// members 
//   pair 
//   pair { "," pair }
private static JsonMembers ProduceJsonMembers(Tokens tokens)
{
    var result = new JsonMembers();

    result.Add( ProduceJsonPair(tokens) );
    while (tokens.LookAhead == TokenTag.Comma)
    {
       tokens.Accept( TokenType.Comma );
       result.Add( ProduceJsonPair(tokens) );
    }

    return result;
}

//pair 
//  string ":" value 
private static JsonPair ProduceJsonPair(Tokens tokens)
{
    var result = new JsonPair();

    result.String = tokens.Accept( TokenType.ID );
    tokens.Accept( TokenType.Colon );
    result.Value = ProduceJsonValue( tokens );

    return result;
}


// and so forth