2015-01-12 8 views
21

Вот короткая версия. Прежде всего: я хочу, чтобы мой класс был неизменным. Я знаю, что класс не может быть абстрактным и окончательным. Я спрашиваю: есть ли способ только позволяют внутренним классам расширять и реализовывать внешний, абстрактный класс? Возможно, это не лучший способ достичь моих неизменных целей, поэтому, если у кого-то есть лучший дизайн, я бы хотел его услышать.Как создать абстрактный, неизменный класс?

Я пишу класс для векторных операций - как в физике, так и в технике, а не в смысле программирования. (Я также знаю, что JScience has a package для такого рода вещей. Я хочу написать свой собственный и сохранить его простым.)

Мне нравится шаблон, используемый в пакете геометрии Java, где, например, можно создать Line2D используя один из двух уровней точности: поплавок или двойной.

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

Это особенность, которую я действительно хотел бы включить и расширить в своем классе, так что я создал следующее:

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 
} 

Очевидно, Vector2D.Integer, Vector2D.Float и Vector2D.Double все окончательные. Есть ли способ сделать Vector2D окончательным для всех, кроме этих внутренних классов?

+0

Кстати, вы не можете использовать дженерики для этого? Большинство операций должны работать с ними, и более идиоматично писать Vector в Java вместо Vector.Integer ... Тогда вам не понадобится все, что кастинг вокруг ... – Falco

+1

@Falco В зависимости от требований к производительности преобразования бокса/распаковки могут (к сожалению, все еще) быть чрезмерно дорогими (последнее, но не менее важное из-за потенциального мусора, подразумеваемого миллионами экземпляров «Double»). Существует причина для специализации, например, «Поток» в Java 8 как «DoubleStream» ...) – Marco13

ответ

25

Есть ли способ, чтобы только внутренние классы, чтобы расширить и реализовать внешний, абстрактный класс?

Да, сделайте конструктор внешнего класса закрытым.

Пример:

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; 
     } 
    } 
} 

Я не думаю, что я когда-либо сталкивался с этим подходом. Заводская схема может быть более гибкой и позволяет разделить потенциально большой класс в несколько файлов. Возможно, также достаточен уровень доступа к пакетам абстрактного класса.

+0

Я забыл об этом подходе. Но разве это не приводит к странному дизайну? –

+0

@LuiggiMendoza, что вы подразумеваете под странным? – aioobe

+0

Я имею в виду, зачем использовать внутренние классы 'static' вместо верхних классов для достижения этой цели? –

10

Есть ли способ, позволяющий внутренним классам расширять и реализовывать внешний, абстрактный класс?

Я бы выбрал другую альтернативу: сделайте ваши абстрактные классы непубличными и опубликуйте только классы реализации final. Это относится к AbstractStringBuilder, что относится к продукту и оценен: java.lang package, is abstract и не public, и это осуществляется StringBuilder и StringBuffer классами, которые являются public final.

Вот соответствующий исходный код этих классов:

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... 
} 
+0

Это может быть отличной альтернативой, если я делаю что-то немного другое. Тем не менее, я ездил только с внутренними классами, потому что они все одинаковы и делают одни и те же вещи, только с разными уровнями точности. Разделение их на отдельные классы добавило бы больше сложности, чем в этом случае. Помимо этого, это отличное решение. – drmuelr

Смежные вопросы