インタビュアーが私に尋ねた:
Observer
とObservable
とは何ですか?また、いつ使用するべきですか?
私はこれらの用語を知らなかったので、私が家に戻り、Observer
とObservable
についてGooglingを始めたとき、私は異なるリソースからいくつかの点を見つけました:
1)
Observable
はクラス、Observer
はインターフェースです。2)
Observable
クラスはObserver
のリストを管理します。3)
Observable
オブジェクトが更新されると、それはそれぞれのObserver
のupdate()
メソッドを呼び出してそれが変更されたことを通知します。
私はこの例を見つけました:
import Java.util.Observable;
import Java.util.Observer;
class MessageBoard extends Observable
{
public void changeMessage(String message)
{
setChanged();
notifyObservers(message);
}
}
class Student implements Observer
{
@Override
public void update(Observable o, Object arg)
{
System.out.println("Message board changed: " + arg);
}
}
public class MessageBoardTest
{
public static void main(String[] args)
{
MessageBoard board = new MessageBoard();
Student bob = new Student();
Student joe = new Student();
board.addObserver(bob);
board.addObserver(joe);
board.changeMessage("More Homework!");
}
}
しかし、なぜObserver
とObservable
が必要なのか理解できません。 setChanged()
メソッドとnotifyObservers(message)
メソッドは何のためのものですか?
生徒とメッセージボードの具体例があります。生徒は、新しいメッセージがメッセージボードに投稿されたときに通知を受けたいオブザーバーのリストに自分自身を追加して登録します。 MessageがMessageBoardに追加されると、Observerのリストを繰り返し処理し、イベントが発生したことを通知します。
Twitterだと思う。あなたが誰かをフォローしたいと言うと、Twitterはあなたを彼らのフォロワーリストに追加します。彼らが新しいツイートを送信したとき、あなたはそれをあなたのインプットに見るでしょう。その場合、あなたのTwitterアカウントはオブザーバであり、あなたがフォローしている人はオブザーバブルです。
Twitterはメディエータになる可能性が高いため、その類似性は完全ではないかもしれません。しかしそれは要点を説明しています。
非常に簡単に言えば(他の答えはとにかく公式のデザインパターンをすべて参考にしているので、詳細はそれらを見てください):
プログラムのエコシステム内の他のクラスによって監視されているクラスを取得したい場合は、そのクラスを観察可能にすることをお勧めします。すなわちプログラムの他の部分にブロードキャストしたいと思うその状態にいくつかの変更があるかもしれません。
さて、これを行うには、ある種のメソッドを呼び出さなければなりません。 Observableクラスを、それを観察することに関心があるクラスと密接に結び付けることは望ましくありません。特定の基準を満たしている限り、誰であるかは関係ありません。 (それがラジオ局であると想像してみてください、彼らが彼らの周波数で調整されたFMラジオを持っている限り誰が聞いていても構いません)。そのために、オブザーバと呼ばれるインタフェースを使用します。
したがって、ObservableクラスにはObservers(つまり、Observerインタフェースメソッドを実装しているインスタンス)のリストが含まれます。何かをブロードキャストしたいときはいつでも、それは単にすべてのオブザーバのメソッドを次々に呼び出します。
パズルを閉じる最後のことは、Observableクラスがどのように興味を持っているのかを知ることです。したがって、Observableクラスは、Observersが自分の興味を登録できるようにするための何らかのメカニズムを提供する必要があります。 addObserver(Observer o)
のようなメソッドはObserverをオブザーバーのリストに内部的に追加するので、何か重要なことが起きたときにリストをループし、リストの各インスタンスのObserverインターフェースのそれぞれの通知メソッドを呼び出します。
インタビューの中で彼らはあなたにJava.util.Observer
とJava.util.Observable
についてはっきりと尋ねなかったが、一般的な概念についてはそうかもしれません。この概念はデザインパターンであり、Javaは必要なときにすぐに実装できるように、すぐにすぐにサポートできるようになっています。だから私はあなたが実際のメソッド/クラス(あなたがそれらを必要なときに調べることができる)よりもむしろ概念を理解することを提案するでしょう。
UPDATE
あなたのコメントに応えて、実際の Java.util.Observable
クラスは以下の機能を提供します。
Java.util.Observer
インスタンスのリストを保守します。通知を受けることに関心のある新しいインスタンスは、addObserver(Observer o)
を通じて追加し、deleteObserver(Observer o)
を通じて削除できます。
オブザーバへの最後の通知以降にオブジェクトが変更されたかどうかを指定して、内部状態を維持します。 Observable
が変更されたと言う部分と、変更を通知する部分が分離されているので、これは便利です。 (例:複数の変更が発生していて、それぞれの小さなステップではなくプロセスの最後にだけ通知したい場合に便利です)。これはsetChanged()
を通して行われます。そのため、何かをObservable
に変更したときにそれを呼び出すだけで、残りのObservers
に最終的にそれを知らせることができます。
特定のObservable
が状態を変更したことをすべてのオブザーバに通知します。これはnotifyObservers()
を通して行われます。これは、通知に進む前に、オブジェクトが実際に変更されたかどうか(つまり、setChanged()
の呼び出しが行われたかどうか)をチェックします。通知とともに追加の情報を渡したい場合に備えて、2つのバージョンがあります。1つは引数なし、もう1つはObject
引数です。内部的には、Observer
インスタンスのリストを繰り返し処理して、それぞれに対して update(Observable o, Object arg)
メソッドを呼び出すだけです。これは変更されたObservableオブジェクトであるObserver
と、追加の情報を潜在的に運ぶための追加のObject arg
(notifyObservers()
を介して渡される)を指示します。
定義
オブザーバパターンは、1つのオブジェクトが変更され、その従属オブジェクトに自動的に通知され、対応する変更がすべての従属オブジェクトに対して行われる場合など、オブジェクト間に1対多の関係がある場合に使用されます。
例
たとえば、あなたの本籍地が変更された場合は、パスポート当局とパンカード当局に通知する必要があります。だからここでパスポート権限とパンカード権限はオブザーバーであり、あなたは主題です。
Facebookでも、もしあなたが誰かを購読しているならば、新しい更新が起こるたびにあなたは通知されるでしょう。
いつ使うか:
あるオブジェクトがその状態を変更した場合、他のすべての依存オブジェクトは一貫性を維持するために自動的にその状態を変更する必要があります。
被験者が観察者の数を知らないとき。
オブジェクトが誰であるかを知らなくても他のオブジェクトに通知できるはずのとき。
ステップ1
件名クラスを作成します。
件名
import Java.util.ArrayList;
import Java.util.List;
public class Subject {
private List<Observer> observers
= new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
ステップ2
Observerクラスを作成します。
Observer.Java
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
ステップ
具象オブザーバクラスを作成する
BinaryObserver.Java
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Binary String: "
+ Integer.toBinaryString( subject.getState() ) );
}
}
OctalObserver.Java
public class OctalObserver extends Observer{
public OctalObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Octal String: "
+ Integer.toOctalString( subject.getState() ) );
}
}
HexaObserver.Java
public class HexaObserver extends Observer{
public HexaObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Hex String: "
+ Integer.toHexString( subject.getState() ).toUpperCase() );
}
}
ステップ4
主題と具象オブザーバオブジェクトを使用します。
ObserverPatternDemo.Java
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
new HexaObserver(subject);
new OctalObserver(subject);
new BinaryObserver(subject);
System.out.println("First state change: 15");
subject.setState(15);
System.out.println("Second state change: 10");
subject.setState(10);
}
}
ステップ5
出力を確認してください。
最初の状態変化:15
六角ストリング:F
オクタル文字列:17
バイナリ文字列:1111
2番目の状態変化:10
六角ストリング:A
オクタル文字列:12
バイナリ文字列:1010
これらは オブザーバデザインパターン の一部です。通常、1つ以上のオブザーバが1つのオブザーバブルの変更について通知を受けます。プログラマーとしてのあなたが「何か」が何を意味するかを定義することができるところで、それは「何か」が起こったという通知です。
このパターンを使用すると、両方のエンティティが互いに切り離されます。オブザーバはプラグ可能になります。
インタビュアーがObserverクラスおよびインターフェースを使用せずに Observer設計パターン を実装するように要求した場合は、次の簡単な例を使用できます。
interface MyObserver {
void update(MyObservable o, Object arg);
}
class MyObservable
{
ArrayList<MyObserver> myObserverList = new ArrayList<MyObserver>();
boolean changeFlag = false;
public void notifyObservers(Object o)
{
if (hasChanged())
{
for(MyObserver mo : myObserverList) {
mo.update(this, o);
}
clearChanged();
}
}
public void addObserver(MyObserver o) {
myObserverList.add(o);
}
public void setChanged() {
changeFlag = true;
}
public boolean hasChanged() {
return changeFlag;
}
protected void clearChanged() {
changeFlag = false;
}
// ...
}
class MessageBoard extends MyObservable {
private String message;
public String getMessage() {
return message;
}
public void changeMessage(String message) {
this.message = message;
setChanged();
notifyObservers(message);
}
public static void main(String[] args) {
MessageBoard board = new MessageBoard();
Student bob = new Student();
Student joe = new Student();
board.addObserver(bob);
board.addObserver(joe);
board.changeMessage("More Homework!");
}
}
class Student implements MyObserver {
@Override
public void update(MyObservable o, Object arg) {
System.out.println("Message board changed: " + arg);
}
}
Observer a.k.aコールバックはObservableに登録されています。
それは通知するために使用されます。ある時点で起こった出来事について。 Swing、Ajax、GWTで広く使われています。 UIイベント(ボタンクリック、テキストフィールドの変更など).
SwingにはaddXXXListener(Listener l)のようなメソッドがあり、GWTには(Async)コールバックがあります。
オブザーバのリストは動的であるため、オブザーバは実行時に登録および登録解除できます。また、インタフェースが使用されるので、オブザーバからオブザーバブルを切り離すのも良い方法です。
「どうして正確にObserverとObservableが必要なのか理解しようとしました」
以前の回答がすでに述べたように、それらはオブザーバを購読してオブザーバブルの自動通知を受け取る手段を提供します。
これが役に立つかもしれないアプリケーションの一例はデータバインディングです。あなたが何らかのデータを編集するUIを持っているとしましょう。データが更新されると、データを観察可能にして、UIコンポーネントをそのデータにサブスクライブすることができます。
Knockout.jsはMVVM javascriptフレームワークで、チュートリアルを順を追って実行することをお勧めします。 http://learn.knockoutjs.com/
私はまた、Visual Studio 2008のスタートページでこの記事を見つけました(オブザーバパターンは、モデルビューコントローラ(MVC)開発の基礎です) http://visualstudiomagazine.com /articles/2013/08/14/the-observer-pattern-in-net.aspx
私はここでオブザーバパターンの簡単な説明を書きました: http://www.devcodenote.com/2015/04/design-patterns-observer-pattern.html
投稿からの抜粋:
オブザーバパターン:それは本質的にオブジェクト間の1対多の関係を確立し、相互依存オブジェクト間の疎結合設計をしています。
TextBookの定義:オブザーバパターンは、オブジェクト間の1対多の依存関係を定義しているため、1つのオブジェクトの状態が変わると、そのすべての依存関係が自動的に通知および更新されます。
たとえば、フィード通知サービスを考えてみましょう。購読モデルは、観察者のパターンを理解するのに最適です。
オブザーバパターンは、1つのオブジェクトが変更された場合、その従属オブジェクトに自動的に通知される場合など、オブジェクト間に1対多の関係がある場合に使用されます。
Java 9以降、両方のインターフェースは推奨されなくなりました。つまり、もう使用しないでください。 を参照してください。ObserverはJava 9では推奨されません。代わりに何を使うべきですか?
しかし、あなたはまだそれらについてのインタビューの質問を受けるかもしれません...