Page 2 of 3
// SlateModel.java import java.awt.Shape; public interface SlateModel { // Listener management public void addSlateModelListener(SlateModelListener l); public void removeSlateModelListener(SlateModelListener l); // Shape repository management, views need notification public void addShape(Shape s); public void removeShape(Shape s); public void removeAllShapes(); // Shape repository read-only operations public int getShapeCount(); public Shape getShapeAtIndex(int index); }
// SlateModelListener.java import java.util.EventListener; public interface SlateModelListener extends EventListener { public void slateChanged(SlateModelEvent event); }
// SlateModelEvent.java import java.util.EventObject; public class SlateModelEvent extends EventObject { public SlateModelEvent(SlateModel model) { super(model); } }
(The source code for DefaultSlateModel, the default implementation for this model, is in the file before/DefaultSlateModel.java.)
Next, we turn our attention to Slate, a view for this model, which forwards its painting task to the UI delegate, SlateUI:
// Slate.java import javax.swing.JComponent; public class Slate extends JComponent implements SlateModelListener { private SlateModel _model; public Slate(SlateModel model) { _model = model; _model.addSlateModelListener(this); setOpaque(true); setUI(new SlateUI()); } public Slate() { this(new DefaultSlateModel()); } public SlateModel getModel() { return _model; } // Listener implementation public void slateChanged(SlateModelEvent event) { repaint(); } }
Finally, SlateUI, the visual GUI component:
// SlateUI.java import java.awt.*; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; public class SlateUI extends ComponentUI { public void paint(Graphics g, JComponent c) { SlateModel model = ((Slate)c).getModel(); g.setColor(c.getForeground()); Graphics2D g2D = (Graphics2D)g; for (int size = model.getShapeCount(), i = 0; i < size; i++) { g2D.draw(model.getShapeAtIndex(i)); } } }
The class structure in the example above does not show the relationship between the classes. To mitigate this, we've used
a naming convention that requires all related classes to have a common prefix, but it would be clearer to show the relationship
in code. Furthermore, developers and maintainers of these classes must manage three files: for SlateModel, for SlateEvent, and for SlateListener, to implement one concept. The same is true with managing the two files for Slate and SlateUI.
We can improve things by making SlateModelListener and SlateModelEvent nested types of the SlateModel interface. Because these nested types are inside an interface, they're implicitly static. Nonetheless, we've used an explicit
static declaration to help the maintenance programmer.
Client code will refer to them as SlateModel.SlateModelListener and SlateModel.SlateModelEvent, but this is redundant and unnecessarily long. We remove the prefix SlateModel from the nested classes. With this change, client code will refer to them as SlateModel.Listener and SlateModel.Event. This is short and clear and does not depend on coding standards.
/before and /after, corresponding to the nonnested and nested examples provided above
goodBy Anonymous on November 4, 2009, 6:29 amgood
Reply | Read entire comment
View all comments