top | item 8875551

(no title)

Proleps | 11 years ago

> If you ever want to change the implementation of Article, you'd break anyone that was using that part of your API. If you use getters, you can change your implementation without breaking the consumers of your API.

Then it wouldn't be immutable, if I can change the implementation I can also create a mutable version.

Edit example

  public class Article {
      private final String title;
      private final String author;
      private final List<String> tags;

      private Article(String title, String author, List<String> tags) {
          this.title = title;
          this.author = author;
          this.tags = tags;
      }

      public String getTitle() {
          return title;
      }

      public String getAuthor() {
          return author;
      }

      public List<String> getTags() {
          return tags;
      }
  }

  public class MutableArticle extends Article {
      private String title;
      private String author;
      private List<String> tags;

      public MutableArticle() {
          super(null, null, null);
      }

      public String getTitle() {
          return title;
      }

      public void setTitle(String title) {
          this.title = title;
      }

      public String getAuthor() {
          return author;
      }

      public void setAuthor(String author) {
          this.author = author;
      }

      public List<String> getTags() {
          return tags;
      }

      public void setTags(List<String> tags) {
          this.tags = tags;
      }

  }

discuss

order

organsnyder|11 years ago

Making a class immutable doesn't mean that the implementation is fixed. If you need to change your implementation to store data differently, the consumers of your API shouldn't need to be modified. The following modification to your first class would still be immutable:

  public class Article {
    private final Author author;
    ...
    public String getAuthor() {
      return author.getName();
    }
  }
Also, your first class isn't fully immutable—getTags should be implemented as follows:

  /**
   * @return Unmodifiable list of tags
   */
  public List<String> getTags() {
    return Collections.unmodifiableList(tags);
  }

Proleps|11 years ago

> Also, your first class isn't fully immutable—getTags should be implemented as follows:

True. It would be nice if Java had some immutable collection classes that don't have mutable methods. A method that gets a List<String> made with Collections.unmodifiableList(tags), doesn't know that it is actually immutable.

potatosareok|11 years ago

For some reason seeing your code really bothers me. Is it normal to ever use private variables in inheritance like that?

Say you had toString() in Article class that returned ("%s%" author, title).

Now if you create a MutableArticle on it, ma.toString() will return null unless you override toString on it as well (since Articles variables are private and not inherited).

I don't code much so I don't know is it normal to see code like that?

Also less relevant but Articles constructor should probably be public?

organsnyder|11 years ago

I agree that this design is sub-optimal. However, if a.toString() called the getters instead of using the instance variables directly, you wouldn't have problems.

The Article class is unusable as provided due to the private constructor (in fact, the MutableArticle class wouldn't even compile), but private constructors can be useful. I often use private constructors and instead provide public static methods that call the constructors. This practice is often derided, and goes into Java's perception as a verbose, arcane language, but it allows for improving an API without breaking clients built to previous versions, as well as making an API more clear (since we can give the static methods more descriptive names).