2012-04-27 6 views
2

Я хочу создать изменяемый и неизменяемый узел в java, оба должны быть одинаковыми во всем, кроме изменчивого. как реализовать базовый класс и два производных класса изменяемых и неизменяемых классов?изменяемые и неизменяемые классы

+0

Что это за «узел»? Каков контекст? Должны ли эти классы быть открытыми для наследования? –

ответ

4

Разница между изменяемыми и неизменяемыми классами заключается в том, что неизменяемые классы не имеют сеттеров или других методов, которые изменяют внутреннее состояние. Состояние может быть установлено только в конструкторе.

Было бы плохо, если бы вызвать родительский класс Immutable, потому что это уже не будет истинным, если у вас есть подклассы. Название должно вводить в заблуждение:

ImmutableNode node = new MutableNode(); 
((MutableNode)node).change(); 
+0

даже без класса сеттеров может быть изменен с использованием отражения. Только конечные переменные гарантируют неизменность – birdy

+0

@myx: Я согласен, что поля * должны быть отмечены как final в неизменяемых классах (но по другой причине, чем вы предлагаете). Однако это не работает, потому что тогда его подклассическая идея невозможна. Измененный класс также не сможет изменить окончательные поля. Хотя, честно говоря, мне не нравится идея использовать наследование для изменчивости в первую очередь. Существуют и другие способы совместного использования кода без использования наследования: например. интерфейсов и композиции. –

+2

@myx --- bzzztt. Вы можете изменять конечные переменные посредством отражения ... кроме статических конечных полей, которые квалифицируются как выражения постоянной времени компиляции. Однако изменение частных и/или конечных переменных посредством отражения рассматривается как практика BAD BAD ... и это должно быть сделано только как отчаянная последняя мера. –

1

Неизменяемый класс - класс, который когда-то был создан, его содержимое не может быть изменено. Неизменяемыми объектами являются объекты, состояние которых не может быть изменено.

Общим примером непреложного класса в Java является класс String.

4

Все, что вам нужно сделать, это создать единый базовый класс с защищенными переменными

public class Base{ 
    protected int foo; 
} 

Мутабельном один должен быть в состоянии установить переменную

public class MutableBase extends Base{ 
    public void setFoo(){} 
} 

В immmutable один должен быть в состоянии для установки переменной только один раз

public class ImmutableBase extends Base{ 
    public ImmutableBase(int foo){ 
      this.foo = foo; 
    } 
} 

Самые непреложные классы, имеющие методы для работы на t он переменный внутри без мутирующий экземпляр. Строка делает это, вы можете что-то вроде этого

public ImmutableBase add(int bar){ 
    return new ImmutableBase(this.foo+bar); 
} 

Самое замечательное в том, что вы даете пользователям вашего класса менее контроль/беспокойство за внутренностей каждого экземпляра. Это упрощает работу, потому что в Java все передается с помощью ссылки на объект, поэтому, если вы проходите вокруг String или ImmutableBase, вам не нужно беспокоиться о том, что он изменяется.

+0

Ошибка компиляции. Если вы сделаете так, 'foo' не может быть закрытым. –

+0

@StephenC - кричит, спасибо – dfb

+0

как насчет объявления этого поля как конечного? – nabil

1

для того, чтобы класс был непреложным, он должен быть объявлен окончательным, и он не должен использовать метод . заключительная декларация гарантирует, что она не может быть расширена и добавлены дополнительные изменяемые свойства.

class Base { 
    protected int var1; 
    protected int var2; 

    public getVar1() {return var1;} 
    public getVar2() {return var2;} 
    } 

    class Mutable extends Base { 
     public setVar1(int var1) {this.var1 = var1} 
     public setVar2(int var2) {this.var2 = var2} 
    } 

    final class Immutable extends Base { //final to avoid being extended and then implement the setters 

    } 

Thats little, котор я могу сделать? Но зачем вам такой сценарий?

+0

как объявить поле в нем как окончательное? – nabil

+0

, потому что он хочет изменчивую версию? если поле окончательно, оно не может быть установлено, но измененная версия требует установки поля. – maress

+0

Хотя только 'final' класс' Foo' может «гарантировать», что экземпляр 'Foo' на самом деле не будет экземпляром какого-либо злого изменчивого производного' Foo', бывают случаи, когда может быть полезно наследовать , даже абстрактный, класс, который указан как непреложный (что означает, что любой производный класс, который является изменяемым, будет считаться «сломанным»). Например, в некоторых контекстах может быть полезно определить абстрактный класс «ImmutableMatrix», деривации которого будут включать «ImmutableArrayMatrix» (с поддержкой массива того же размера, что и матрица), «ImmutableConstantMatrix» (подкреплено ... – supercat

1

Другой вариант - использовать ту же стратегию, что и UnmodifiableList. Сначала создайте интерфейс, определяющий тип.

interface List<T>{ 
    List<T> add(T t); 
    T getAt(int i); 
    ... 
} 

Тогда вы реализуете свой изменяемый класс со всей бизнес-логикой:

public class MutableList<T> implements List<T>{ 
    @Override 
    List<T> add(T t){ ... } 

    @Override 
    T getAt(int i){ ... } 

    ... 
} 

И, наконец, создать свой неизменный класс быть видом изменяемома один. Вы реализуете один и тот же интерфейс, но делегируете все вызовы метода чтения просмотренному объекту и запрещаете любой доступ на запись с помощью Исключения.

public class UnmodifiableList<T> implements List<T>{ 
    //This guy will do all hard work 
    private List delegate; 

    public UnmodifiableList(List<? extends T> delegate){ 
     this.delegate = delegate; 
    } 

    //Forbidden mutable operation: throw exception! 
    @Override 
    List<T> add(T t){ 
     throw new UnsupportedOperationException("List is unmodifiable!"); 
    } 

    //Allowed read operation: delegate 
    @Override 
    T getAt(int i){ 
     return delegate.getAt(i); 
    } 

    ... 
} 

Этот подход имеет то преимущество, что вы реализовать бизнес-логику только один раз, и может сначала построить объект, используя свои собственные методы и проверки достоверности, прежде чем превратить его в imutable объекта.

+0

Важно отметить различие между объектами, которые предоставляют представления только для чтения потенциально изменяемых объектов, и те, которые предоставляют представление только для чтения объекта, который они создают сами, и никогда не выставляются в любом контексте, который может его изменить. Термин «неизменяемый» в этом отношении несколько расплывчатый. Я предпочитаю такие термины, как «ReadableFoo», ссылаться на вещи, которые, как известно, читаемы и не могут быть * напрямую изменены, но могут измениться с помощью других средств и «ImmutableFoo», чтобы ссылаться на вещи, которые гарантированно никогда не изменяются, период. «Немодифицируемый» кажется странной средой. – supercat

+0

Да, ты прав. Владелец исходного списка может изменить его содержимое, и это будет отображаться в представлении. С другой стороны, представление является гораздо более эффективным, вычислительным и запоминающим. Правильный инструмент зависит от того, что используется, и, к сожалению, ассер не предоставил много информации об этом ... –

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