开发者

Design of a Bot class capable of returning Answer objects for all sorts of Question objects

I'm trying to build a GraphBot class that can answer different questions about about an associated graph such as path length, shortest path between two vertices, number of paths passing through a given vertex etc.

I'd like to be able to add new questions without changing any code inside the Bot, it is only responsible for receiving the question, delegating so some other algorithm to solve the question using the graph associated with the bot and returning the answer.

So something like this:

public class GraphBot {
    private Graph graph;

    public GraphBot(Graph graph) {
        this.graph = graph;
    }

    public Answer ask(Question question) {
        // delegate somehow to answer the question, providing the graph
        // return an Answer object encapsulating the answer
    }
}

public interface Answer {
    public toPrintableOutput();
}

public interface Question {
    // question methods go here... this is what I'm having trouble with
}

The trouble I'm having is that questions have associated conditions or parameters. For instance, the question "path length" between "A" and "B" has the question type ("path length") which is something all questions will have, but also the parameters "A" and "B". In comparison, the question "paths passing through vertex" will only have the parameter "C" representing the vertex.

I can't think of a way of presenting a uniform interface so that the system can be easily extended to handle numerous different questions with different numbers and types of parameters. I could have a QuestionSolver that was associated with each Question in which case it wouldn't matter if each Question had different attributes as the QuestionSolver could assert that the question is of a valid type but this would require a mapping of Question to QuestionSolver somewhere that would require updating whenever a new question is introduced.

What is the most extensible way of implementing this system so that new questions would not require tonnes of changes in loads of different classes? Really I want to be able to create an class implementing Question and maybe create a class that can solve that question and then have t开发者_运维技巧he GraphBot automatically able to handle that question.


What you can do is just have the ask() method be part of the Question interface, and take a Graph. That way, each Question has to know how to answer itself, and you don't have to design a Question api that is future-extensible.

EDIT: Why is this a better design than making the GraphBot be able to answer a Question?

  • Simplicity: As you're finding out, it's very hard to design a Question API that will take every possible data required into account for any question as well as figuring out how to compile that into a dynamic question asking algorithm. It's much simpler to have custom code per Question that will know what to do with the publicly known Graph data.
  • Depndencies: Your initial approach makes the relatively stable GraphBot dependent on the definitely unstable Question. My approach reverses this dependency, making it all much simpler, which leads back into the last point.
  • Maintenance: I guarantee you wouldn't be able to predict everything the Question class needs to make available. When (not if) you come across a change you need to make in the Question interface, every implementer will need to change. This will make your future you (or some other developer) hate your present you with the fiery passion of a thousand suns if there are more than a few Question implementers.

In the end, I can't think of a convincing reason to not make a question answer itself. Yes, it's arguable that it doesn't make a lot of sense from a purely abstract "does this align with the real world" point of view, but it's both practical and not unreasonable for a question to handle it's own answering. One thing to remember about OOP is that the similarities with the real world are for convenience, not as a rule. Don't let yourself be straitjacketed by them.

So now it would be like this:

public class GraphBot {
    private Graph graph;

    public GraphBot(Graph graph) {
        this.graph = graph;
    }

    public Answer ask(Question question) {
        return question.ask(graph);
    }
}

public interface Answer {
    public toPrintableOutput();
}

public interface Question {
    public Answer ask(Graph graph);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜