an alternative approach to layouts
 
Here’s a quick sketch of a way to implement layouts without (requiring) layout managers. This idea occurred to me because I’m doubtful now about a design where components have a writable location property. As Alan Holub points out in his article of the same name, “setters are evil.”

public interface Locator {
    Location getLocation();
}

public interface Location extends Locator {
    public int getX();
    public int getY();
}

public abstract class Component implements Location{
    ...
    public abstract Locator getLocator();
}

What’s interesting about this design is that the location of a component is only defined by a subclass. This actually makes good sense to me as a component in the abstract doesn’t have a location. One effect of this structure is that every component does not have to have field(s) for location. Another is that you get an extremely powerful and reliable programmatic layout pattern using anonymous classes (although this could be more concise in a language that supported closures and mix-ins like my “type enhancers”):

add(component1 = new Component1(...) {
    public Locator getLocator() {  
        return new FixedLocation(getParent().getWidth() - getWidth() - 10,
                                 getParent().getHeight() - getHeight() - 10);
    }
}
add(component2 = new Component2(...) {
    public Locator getLocator() {  
        return new FixedLocation(component1.getX(),  
                                 component1.getY() - getHeight() - 10);
    }
}

And naturally, you can create all kinds of interesting locator implementations very easily, including all the functionality you can currently get with layout managers, but additionally locators that do things like vary location over time (to do component animations).
You could further breakdown the Location interface to allow composition of locating algorithms for both axes:

public interface Location extends HorizontalLocation, VerticalLocation, Locator {
    public int getX();
    public int getY();
}
 
public class LeftOf implements HorizontalLocation {
    ...
}
 
public class RightOf implements HorizontalLocation {
    ...
}
 
public class Centered implements HorizontalLocation {
    ...
}
Sunday, May 18, 2008