4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Observerパターンの基本を、クラス図とコードを使って説明

Last updated at Posted at 2020-02-16

おす、やまうちです。
エンジニア歴3ヶ月弱なうです。
偉くてすごい人達は朝早く起きて活動している聞いて、朝活をしております。
(いいと思ったものは積極的に取り入れていくスタイル)
ちなみに、これ書いてるのは朝じゃないですw

そして現在学習している本、『アジャイルソフトウェア開発の奥義』。
この本で、Observerパターンなるものが出てきました。
深く理解したわけではないのですが、1ミリでも深く理解するために自分の考えをまとめたいと思います!
まだまだ浅瀬なんですけどね。。。

アジャイルソフトウェア開発の奥義

サンプルケース

とある学習塾にて、先生が生徒の学習時間を管理しているという設定。

一旦Observerパターンを使わないやつ

Observerパターンではない一番シンプルな設計が以下です。
Untitled Diagram (17).png
生徒が先生に報告(Report)しています。
先生の方では受け取った報告をもとに情報を更新(Update)します。

ちなみにですが、Observerパターンにおいて、「観察者」と「通知者」という考え方があり、今回の場合ですと「先生が観察者」で「生徒が通知者」になります。
コードはこんな感じ。

class Student
{
    private Teacher teacher;
    private String studentName;

    public Student(Teacher teacher, String studentName)
    {
        this.teacher = teacher;
        this.studentName = studentName;
    }

    public void report(int studyTime)
    {
        teacher.update(this.studentName, studyTime);
    }

}

class Teacher
{
    public void update(String studentName, int studyTime){
        System.out.println(studentName + "の勉強時間は" + studyTime + "です");
    }
}

このくらいなら特に問題もなさそうですが、少し生徒を増やしてみましょう。
Untitled Diagram (18).png
う~ん、まだセーフ?
生徒が増える分には問題は生じてないですね。
通知者である生徒それぞれに変化がないので。

ではちょっと問題がある感じにしていきましょう!

先生が増えたり変わると問題が発生

内容としてはいつもの先生(Teacher)が休みだったため、別の先生(TeacherB)に報告することにしましょう。
観察者の交代です。
こんな感じ。
Untitled Diagram (19).png

一番上のTeacherがTeacherBに変わってますね。
そこまで大きな変化はないように見えますが、そんなことはありません。
報告(report)する先生を変える必要がありますので、こんなことが必要になります。

// Studentクラスに追加
public void setTeacher(Teacher teacher)
{
    this.teacher = teacher;
}

studentA.setTeacher(teacherB);
studentB.setTeacher(teacherB);
studentC.setTeacher(teacherB);

う~ん、問題あり!w

これでは先生が変わるたびに生徒の報告先を変えなければならないので、生徒が多ければ多いほど悲しみが深いです。。。
これに対応するのが、Observerパターンです!

Observerパターンに変更

とりあえずクラス図を!
Untitled Diagram (23).png
いきなり雰囲気が変わりました(;・∀・)
StudentにもstudentNameとstudyTimeのゲッターを実装しました。
慌てず増えたSubjectクラスとObserverクラスについて掘り下げましょう。

Observerクラス

これは観察者側に存在するインターフェースです。
Observerという単語の意味が観察者ですね。
TeacherクラスはObserverインターフェースを実装しています。
Observerを通して、観察者である先生は通知者である生徒の報告を受け取ります。
ここは特に難しいことはないです。

public interface Observer
{
    public abstract void update(Subject subject);
}

Subjectクラス

こちらは色々書いてあるのでゆっくり見ていきましょう。
まずこれはStudentクラスの親になる、抽象クラスです。
この抽象クラスで、先生(Observer)を管理しています。
先生を管理する変数observersは、リストなので何人でも管理できます!

続いてnotifyObserverというメソッドですが、こちらで上記のリストで管理している先生(Observer)全員に対して、生徒から受け取った報告をしていきます。
やっていることはこれだけです!w

addObserverは先生を追加したいときに使うメソッドです。

他に定義しているメソッドは抽象メソッドで、子クラスであるStudentクラスで実装します。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public abstract class Subject
{
    // ここで先生を管理、リストなので何人でもOK
    public List<Observer> observerList = new ArrayList();

    abstract public void report(int studyTime);
    abstract public String getStudentName();
    abstract public int getStudyTime();

    protected void notifyObserver()
    {
        Iterator<Observer> i = observerList.iterator();
        while (i.hasNext())
        {
            Observer observer = i.next();
            observer.update(this);
        }
    }

    public void addObserver(Observer observer)
    {
        observerList.add(observer);
    }
}

流れとしてはこんな感じ

  1. Studentクラスのreportを実行
  2. reportメソッドの中で、親クラスのnotifyObserverを呼び出す
  3. notifyObserverメソッドの中で、Observerインターフェースのupdateを呼び出す
  4. Observerインターフェースを実装している、Teacherクラスのupdateを実行

まとめ

Observerパターンを取り入れることで、他を一切変更することなく、今回の例でいう先生をいくらでも増やせる状況を作れます。
神っ。
これを使いこなすことができればレベルがあがる気がする。
とはいえ本にはこうも書いてあった。

Observerパターンを乱用すると、理解しにくく、流れを追いかけるのが難しいシステムになりやすい。
『アジャイルソフトウェア開発の奥義 P397』より引用

まじかよ。
使えるだけじゃだめで、タイミングまでも見極める必要があるとは。。。
先は長い(;´Д`)

最終的な全体のコード

Observer.java

public interface Observer
{
    public abstract void update(Subject subject);
}

Teacher.java

public class Teacher implements Observer
{
    public void update(Subject subject){
        String name = subject.getStudentName();
        int studyTime = subject.getStudyTime();
        System.out.println(name + "の勉強時間は" + studyTime + "分");
    }
}

Subject.java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public abstract class Subject
{
    private static List<Observer> observerList = new ArrayList();

    abstract public void report(int studyTime);
    abstract public String getStudentName();
    abstract public int getStudyTime();

    protected void notifyObserver()
    {
        Iterator<Observer> i = observerList.iterator();
        while (i.hasNext())
        {
            Observer observer = i.next();
            observer.update(this);
        }
    }
    public void addObserver(Observer observer)
    {
        observerList.add(observer);
    }
}

Student.java

public class Student extends Subject
{
    private String studentName;
    private int studyTime;

    public Student(String studentName)
    {
        this.studentName = studentName;
    }

    public String getStudentName()
    {
        return studentName;
    }

    public int getStudyTime()
    {
        return studyTime;
    }

    public void report(int studyTime)
    {
        this.studyTime = studyTime;
        notifyObserver();
    }
}

Main.java(2パターンの実行)

public class Main {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        Student student = new Student("Mike");
        student.addObserver(teacher);
        student.report(10);
    }
}
Mikeの勉強時間は10分
public class Main {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        Teacher teacher1 = new Teacher();
        Student student = new Student("Mike");
        Student student1 = new Student("Bob");
        student.addObserver(teacher);
        student.addObserver(teacher1);
        student.report(10);
        student1.report(40);
    }
}
Mikeの勉強時間は10分
Mikeの勉強時間は10分
Bobの勉強時間は40分
Bobの勉強時間は40分

先生と生徒がそれぞれふえてもちゃんと動く!
(先生2人 × 生徒2人 で4件の出力)

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?