正方形の周長 #23

知らせる情報を表すクラスと知らされる側が持つべきインタフェイスについて定義したので、
今度は知らせる側を作成する。
正方形の諸元を表すSquareParametersにその変更を知らせる機構を付加したクラスSquareを定義する。

Square.java
import java.util.concurrent.CopyOnWriteArrayList;

public class Square extends SquareParameters {
    @Override
    public void setSide(double side) {
        super.setSide(side);
        fireSquareChanged(new SquareEvent(this));
    }

    @Override
    public void setPerimeter(double perimeter) {
        super.setPerimeter(perimeter);
        fireSquareChanged(new SquareEvent(this));
    }

    private CopyOnWriteArrayList<SquareListener> listeners = new CopyOnWriteArrayList<>();

    public void addSquareListener(SquareListener listener) {
        if (listener != null) listeners.addIfAbsent(listener);
    }

    public void removeSquareListener(SquareListener listener) {
        if (listener != null) listeners.remove(listener);
    }

    public void fireSquareChanged(SquareEvent e) {
        for (SquareListener listener : listeners) listener.squareChanged(e);
    }
}

一辺の長さや周の長さを新たに設定したときに予め登録されていたSquareListenerのsquareChangedメソッドを呼び出す。
CopyOnWriteArrayListは登録や削除するコストがかなり高くつくが、
リスト内の要素を走査する際にいちいち同期化しなくていいので、
リストの変更より走査が多いような場合には効率が良くなる。
addSquareListenerメソッドでSquareListenerを登録する場合に、
CopyOnWriteArrayList#addIfAbsentメソッドを使っているのは、
同じものを二重登録するのを防止するためである。