Как я могу преобразовать это в более управляемый код? - PullRequest
9 голосов
/ 16 апреля 2010

Является ли этот код достаточно сложным, чтобы заслуживать более высокого уровня абстракции?

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 ]

10 голосов
/ 16 апреля 2010

Не рассматривая его подробно, поскольку вы анализируете на основе состояния, не могли бы вы использовать шаблон состояния , чтобы разбить его и проанализировать каждый бит в отдельном классе на основе состояния?

что-то вроде этого может быть началом, хотя это просто псевдокод ...

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);
            }
        }
2 голосов
/ 19 апреля 2010

«Концептуальный дизайн» в данном случае - это правила производства. Если бы вы спроектировали Json самостоятельно, вы бы подумали с точки зрения «пара - это ключ, за которым следует двоеточие, за которым следует значение», или вы бы подумали с точки зрения «двоеточия будут делать« а »в этом случае« А »и делать '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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...