Immutable对象

翻译自Oracle教程。http://docs.oracle.com/javase/tutorial/essential/concurrency/syncrgb.html

我们先来定义一个表示颜色的类,

public class SynchronizedRGB {

    // Values must be between 0 and 255.
    private int red;
    private int green;
    private int blue;
    private String name;

    private void check(int red,
                       int green,
                       int blue) {
        if (red < 0 || red > 255
            || green < 0 || green > 255
            || blue < 0 || blue > 255) {
            throw new IllegalArgumentException();
        }
    }

    public SynchronizedRGB(int red,
                           int green,
                           int blue,
                           String name) {
        check(red, green, blue);
        this.red = red;
        this.green = green;
        this.blue = blue;
        this.name = name;
    }

    public void set(int red,
                    int green,
                    int blue,
                    String name) {
        check(red, green, blue);
        synchronized (this) {
            this.red = red;
            this.green = green;
            this.blue = blue;
            this.name = name;
        }
    }

    public synchronized int getRGB() {
        return ((red << 16) | (green << 8) | blue);
    }

    public synchronized String getName() {
        return name;
    }

    public synchronized void invert() {
        red = 255 - red;
        green = 255 - green;
        blue = 255 - blue;
        name = "Inverse of " + name;
    }
}

在多线程环境下,

SynchronizedRGB color =
    new SynchronizedRGB(0, 0, 0, "Pitch Black");
...
int myColorInt = color.getRGB();      //Statement 1
String myColorName = color.getName(); //Statement 2

如果你在语句1和语句2之间有个线程调用setter方法改变颜色的RGB值,那么输出的颜色值和名称就会不匹配。

怎么解决呢?简单的方法是使用同步。

synchronized (color) {
    int myColorInt = color.getRGB();
    String myColorName = color.getName();
} 


还有一种从设计上根除的方法,就是构造一个不可变类 (Immutable Object)。

下面给出简单的策略。虽然有些Immtuable类不完全符合这些策略,但这并不意外着他们不仔细,因为他们有理由确保它们的实例不会在构造后被修改。

  • 不提供setter方法
  • 使所有的属性为private和final
  • 不允许子类重写方法。最简单的方法是将类声明为final,但更好的做法是使构造函数私有,然后提供一个提供实例的工厂方法
  • 如果实例的属性包含对可变对象的引用,不能允许这些对象被修改不提供修改可变对象的方法;不共享对可变对象的引用;不要保存引用外部的变量,不要保存传递到构造器的可变对象;如果 必要的话,创建拷贝在保存。


final public class ImmutableRGB {

    // Values must be between 0 and 255.
    final private int red;
    final private int green;
    final private int blue;
    final private String name;

    private void check(int red,
                       int green,
                       int blue) {
        if (red < 0 || red > 255
            || green < 0 || green > 255
            || blue < 0 || blue > 255) {
            throw new IllegalArgumentException();
        }
    }

    public ImmutableRGB(int red,
                        int green,
                        int blue,
                        String name) {
        check(red, green, blue);
        this.red = red;
        this.green = green;
        this.blue = blue;
        this.name = name;
    }


    public int getRGB() {
        return ((red << 16) | (green << 8) | blue);
    }

    public String getName() {
        return name;
    }

    public ImmutableRGB invert() {
        return new ImmutableRGB(255 - red,
                       255 - green,
                       255 - blue,
                       "Inverse of " + name);
    }
}


你可能感兴趣的:(Immutable,重学Java)