design-patternsoopinterface-design

High level design pattern for image editing tools


I have recently begin creating an image editing tool which will cater to a very specific need. This is as much for the people who are going to use it as it is for my own entertainment. however, I have hit a bit of an architectural snag early on.

Like any image editor, the user will use 'tools' to draw on and manipulate an image. My first attempt at this consisted of a simple interface:

public interface IDrawingTool
{
    void DrawEffect( Graphics g );
    // other stuff
}

This (I thought) would be nice and clean and would allow for easy maintenance and extension. Just add the interface objects in and call the DrawEffect method of the selected one at runtime.

The problem with this approach is that different drawing tools do not cleanly adhere to a single interface. For example, a pen tool need only know the point to draw at in order to work. The rectangle however needs the first point clicked, as well as the current position. The polygon tool needs to keep track of multiple mouse clicks.

I am having trouble thinking of a nice way to implement this. The best method that I can think of now would involve a switch statement and a case for each tool, which would mean that the drawing logic would be in the Canvas class, not encapsulated by Tool type objects. because this is practice, I would like to do this the right way. Thanks for any help in advance.


Solution

  • Okay, rule of thumb: if you see a switch statement in your code sketch, it's a sign you need to use polymorphism instead. So, in this case, you want to be able to have various operations, and you're finding yourself wanting a switch, so you should think "how can I make this something using polymorphism?"

    Now,have a look at the Command pattern, where your objects are verbs instead of nouns. Each Command implements a doThis() method; when you construct the object, you establish what the command wil do.

    public interface Command {
       public void doThis(Graphics g);  // I don't promise returning 
                                        // void is the best choice
       // Would it be better to return a Graphics object?
    }
    
    public class DrawRectangle implements Command {
       public DrawRectagle( Point topLeft, Point btmRight) { // ...
       }
       public void doThis(Graphics g){ // ...
       }
    }
    

    Now, consider what you would do if you wanted to implement undo?

    Update

    Okay, let's extend this a bit more. The point of using this pattern is to make sure the client doesn't need to know all that much, except when you're doing the original construction. So for this example, let's think about drawing a rectangle. When you picka Rectangle tool, you're going to have some code on the button-click event handler (this is all pseudocode btw)

     cmdlist = [] // empty list
     bool firstClick = true
     Point tl = br = new Point(0,0)
     onClick:
       if firstClick:
         get mouse position into tl
         firstClick = false
       else:
         get mouse position into br
         cmdlist.append(new DrawRectangle(tl, br))
         firstClick = true
    

    So now when you've picked out the rectangle, you add a DrawRectangle object to the command list structure. Sometime later, you run through the list

    for cmd in cmdlist:
       cmd.doThis(Graphics g)
    

    and these things get done. It should be obvious now that you would implement undo by adding an "undoThis" method to Command. When you create a command, you have to buuild code so that the object will know how to undo itself. Then undo means just taking the last Command object off the list and doing its undoThis method.