2

I'm designing a vector drawing app.

I need to implemente copy and paste, shapes insertion, deletion and transforming while still being capable of including new tools with easy in the future.

The way I think about it, this is a finite state machine, so i thought about a State Pattern. The stage behaves differently based on it internal state. Each state would be a tool.

Diagram showing tools

var stage = new StageManager();

var insert = new InsertTool();
var copy = new CopyTool();
var paste = new PasteTool();
var select = new SelectTool();

stage.registerTool(insert);
stage.registerTool(copy);
stage.registerTool(paste);
stage.registerTool(select);

If, say, user just pasted a shape, StageManager transitions to selection mode (SelectTool).

onMouseUp(event){
    this.stageManager.addShapes(this.stageManager.clipboard.getAll());

    // Just pasted, transition to selectionTool
    this.stageManager.chooseTool('selection-tool');
}

// From now on, stage behaves like a selectionTool.

Is that a wise architecture for a diagram app?

  • 1
    Why do tools need about each other in order for the program to transition from one tool to another? – Tulains Córdova Sep 10 '16 at 0:17
  • @TulainsCórdova I updated the question to remove that paragraph. Tools or StageManager need to do the transition. If tools do, they need to know about the other tools. – motobói Sep 10 '16 at 1:17
  • Doesn't that languages have types? – Tulains Córdova Sep 10 '16 at 1:22
  • Now I understand the transition thing. But thety do not need to know about each other. They only need to know the name or identifier of the next state. I'll put that in an answer. – Tulains Córdova Sep 10 '16 at 1:26
  • This tells you what tool is selected. But what color is selected? What keyboard keys are held down? Shift? Ctrl? Your real needs are just the state of this one tool? – candied_orange Sep 10 '16 at 1:34
2

I think it's a good architecture to begin with. There's a way for states to make a transition without knowing too much about each other. They just need to know the interface and a key.

I'll assume your language supports interfaces and that all tools implement the tool interface.

  • Create global constants, one for each state.
  • When you register the states do it in a map/dictionary collection. You put the tool and its "ID" in the map. That way you can retrieve them from the map using that key (the corresponding constant).
  • Each tool have a list of possible next states, which could have zero, one or more possible "next states" it can transition to. BUT that list doesn't contain the tools themselves but their key.
  • Then inside the implementation of each tool you can decide which tool to transition to and get them from the registry using their key.

This answer to another question shows working code in Java of a state machine where each state transitions to the most appropiate "next state". The example is about a car whose behavior is modeled as a finite state machine. In that example the states are inner classes of the class that contains them (as opossed to injected), and thus they have access to the collection of states (equivalent to the collection of tools you have in ToolManager when you register tools. But you can find a way to do the same thing without the tools (which are states). One way is injecting a callback into the tools when you register them so that they can get the instance of the tool they need to transition to from the collection of registered tools of the manager by the corresponding key.

If you decide the transitions in the manager, you will end up with a if-then-else or switch-case mess.

At the moment of registering you can also inject a context object (singletons) into the tools so they have access to what color is selected, etc.

Also you would like to implement the command pattern in order to support undo operations.

  • 2
    I understand now that I was looking in the wrong place. As state pattern models a state machine, there is no way one can simply create new states. It's necessary to update all states with the new transitions. – motobói Sep 10 '16 at 2:58
  • @motobói Not sure I understood what you mean. – Tulains Córdova Sep 10 '16 at 3:04
  • I was looking for a solution which would automatically accommodate future changes. Something like a plugin system where I would simple register new tools and they would magically work. Now I see that if I am modeling a finite state machine, each state map to a state class and I must arrange transitions and events where they occur. If I introduce another state, I must rearrange the model to deal with it. – motobói Sep 10 '16 at 3:57
  • 2
    @motobói I think the only state that must be known by all other states is SelectionTool. All tools must transition to SelectionTool after they do their work. Manager can set SelectionTool as the nextState for all tools as they are registered. Load classes from files (your language must allow you to load classes from disk, like Java's ClassLoader) for you to be able to automatically accommodate new tools that didn't exist during compile time as long as they implement the Tool interface. – Tulains Córdova Sep 10 '16 at 4:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.