문제

Suppose you have a class Dog, that has

public class Dog {

    private String name;
    private double age;

    // some setters
    // some getters

Additionally, you have a class DogHandler, that makes an instance of the Dog d and passes it to Owner

I suppose, i can

... make a copy of a Dog before passing it to Owner, but that's an expensive operation and i'd rather avoid it.

... come up with an interface that Dog implements which contains getters only, cast Dog to that interface and pass the result along

... initialize settable variables in a constructor and simply not allow changes for this instance of an object

Are there any other ways to make sure receiver of the object cant modify it?

How do you take a simple bean containing some data and make it read-only?

도움이 되었습니까?

해결책

This can be achieved in few ways, I can propose you 2 of them:

a) interface with getters is good idea

b) create derived class from Dog which has setters method blocked, like this:

class UnmodifiedDog extends Dog {
    public UnmodifiedDog(double age, String name) {
        super.setAge(age);
        super.setName(name);
    }
    @Override
    public void setAge(double age) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setName(String name) {
         throw new UnsupportedOperationException();
    }   
}

In DogHandler:

Dog createDog() {
    return new UnmodifiedDog(10, "Fido");
}

and you can pass this to the Owner:

owner.receiveDog(dogHandler.createDog());

다른 팁

The approaches you mention in the question are pretty much the standard steps to take to make Dog immutable. The only other tip would be to mandate that Dog cannot be overridden by declaring the class to be final.

Among the solutions mentioned here, you can also take advantage of visibility modifiers. If Dog and Owner are in separate packages, you can set the visibility of the mutators to default (package) scope or protected scope.

This will allow you to keep Dog and DogHandler in the same package (and therefore allow them both to mutate the Dog object accordingly), while keeping Owner objects separate (and therefore preventing them from making any modification to the Dog objects).

Here is an example using an interface and package access setters.


package blah.animal;
public interface Dog
{
  double getAge();
  String getName();
}

package blah.animal;
public class DogImpl implements Dog
{
  private double age; // double seems wrong for age.
  private String name;

  ... getters (defined by Dog interface)

  // package access setters.
  void setAge(double newValue)
  {
    age = newValue;
  }

  void setName(String newValue)
  {
    name = newValue;
  }

  package blah.animal;
  public class DogHandler
  {
    public static Dog newDog(double age, String name)
    {
      Dog returnValue = new DogImpl();
      returnValue.setAge(age);
      returnValue.setName(name);

      return returnValue;
    }
  }

  package.blah.somethingelse;
  public class Blam
  {
    private Dog myDog;

    public Blam()
    {
      myDog = DogHandler.newDog(1.4D, "Tippy");
    }
  }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top