drmuelr
drmuelr

Reputation: 1125

How can one create an abstract, immutable class?

Here's the short version. First and foremost: I want my class to be immutable. I know that a class can't be both abstract and final. What I'm asking is: is there a way to only allow inner classes to extend and implement the outer, abstract class? This may not be the best method to achieve my immutable goals, so if somebody has a better design, I would love to hear it.

I am writing a class for vector operations -- as in physics and engineering, not the programming sense. (I'm also aware that JScience has a package for this kind of stuff. I want to write my own, and keep it simple.)

I like the pattern used in Java's geometry package, wherein, say, a Line2D can be created using one of two precision levels: float or double.

public abstract class Line2D {
    public static class Float extends Line2D { /* Implementation */ }
    public static class Double extends Line2D { /* Implementation */ }
}

This is a feature I would really like to incorporate and expand upon in my class, so I created the following:

public abstract class Vector2D {

    public final static class Integer extends Vector2D {

        // Component length projected along x/y axis, respectively
        final private int i, j;

        public Integer( int i, int j ) {
            this.i = i;
            this.j = j;
        }

        public Object doStuff() { /* vector operations */ }
    }

    public final static class Float extends Vector2D {
        // Identical to Vector2D.Integer, except with floats
    }

    public final static class Double extends Vector2D { /* Same Idea */ }

    // Outer class methods and whatnot
}

Obviously, Vector2D.Integer, Vector2D.Float, and Vector2D.Double are all final. Is there any way to make Vector2D final to everything except these inner classes?

Upvotes: 22

Views: 4145

Answers (2)

aioobe
aioobe

Reputation: 421090

Is there a way to only allow inner classes to extend and implement the outer, abstract class?

Yes, make the constructor of the outer class private.

Example:

abstract class MyAbstractClass {
    int i; // some property
    private MyAbstractClass(int i) {
        this.i = i;
    }

    public static class InnerConcrete extends MyAbstractClass {
        int j; // some other property
        public InnerConcrete(int i, int j) {
            super(i);
            this.j = j;
        }
    }
}

I don't think I've ever come across this approach. A factory pattern may be more flexible and allows you split the otherwise potentially large class into several files. Package access level of the abstract class may perhaps also be sufficient.

Upvotes: 25

Luiggi Mendoza
Luiggi Mendoza

Reputation: 85779

Is there a way to only allow inner classes to extend and implement the outer, abstract class?

I would opt for another alternative: make your abstract classes non-public and only make public the final implementation classes. This is the case of AbstractStringBuilder, which belongs to java.lang package, is abstract and non-public, and it's implemented by StringBuilder and StringBuffer classes, which are public final.

Here's the relevant source code of these classes:

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    //implementation details...
}

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence {
    //implementation details...
}

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence {
    //implementation details...
}

Upvotes: 10

Related Questions