/*
Observeパターンでは、ルーラーを受け取りたいオブザーバーは、内容が変更されたイベントを購読する必要があります。Subscribe/Publish パターンは、サブスクライバとパブリッシャの間に位置するトピック/イベントチャネルを使用します。このイベントシステムによって、サブスクライバーが必要とする値を含むカスタムパラメータを渡すことができる、アプリケーション固有のイベントをコードで定義することができます。目標は、サブスクライバーとパブリッシャーが依存しないようにすることです。
オブザーバーパターンとの違いは、サブスクライバーが適切なイベントハンドラを実行することで、パブリッシャーからの通知を登録し受け取ることができるという点です。
オブザーバパターンのターゲットオブジェクトはオブザーバを維持する責任があります。パブリッシュ/サブスクライブパターンのパブリッシャーは、サブスクライバーのことは気にしません。オブザーバーパターンでは、オブザーバーはインターフェースを提供する必要があります。そして、ターゲットオブジェクトが変更されると、このインターフェースが呼び出され、ターゲットの状態と一致するようにします。つまり、全てのオブザーバーは統一されたインターフェイスを必要とします。 パブリッシュ/サブスクライブモデルでは、サブスクライバーイベントはそのようなインターフェイスによってトリガーされるのではなく、サブスクライバーがリスニングしている特定のメッセージによってトリガーされます。 サブスクライバーはパブリッシャーをリスニングしているのではなく、メッセージのプールをリスニングしていると理解することができます。サブスクライバーはパブリッシャーではなく、メッセージプールをリスニングしていると理解できます。このメッセージを誰が発行したかは関係ありません。
class Observe{
constructor() {
this.handlers = {};
}
// 登録イベントをバインドする
register(type, hander) {
// 登録されたイベントタイプが以前に登録されていない場合、登録は直接行われる
if (!this.handlers.hasOwnProperty(type)) {
this.handlers[type] = []
}
this.handlers[type].push(hander)
return this
}
// イベントをトリガーする
emit(...args) {
let type = Array.prototype.shift.call(args)
if (this.handlers.hasOwnProperty(type)) {
// console.log(this.handlers[type])
this.handlers[type].forEach(item => {
// console.log(item)
item.apply(item, args)
});
} else {
throw new Error(`${type} event isn't register`)
}
return this
}
}
let observe = new Observe();
observe.register('hello', function(a) {
console.log(a)
})
observe.emit('hello',[1,2,4])
observe.emit('word',2)
// オブザーバーパターン
function ObserveList() {
this.observeList = [];
}
// オブザーバーにメソッドを追加
ObserveList.prototype.add = function (obj) {
return this.observeList.push(obj);
}
// のオブザーバーの数を数えます。
ObserveList.prototype.count = function () {
return this.observeList.length;
}
// 現在のオブザーバー内の特定のオブザーバーを取得します。
ObserveList.prototype.get = function (index) {
if (index > -1 && index < this.observeList.length) {
return this.observeList[index]
}
}
// オブザーバ内のインデックスを取得
ObserveList.prototype.indexOf = function (obj, startIndex) {
let i = startIndex || 0;
while(i < this.observeList.length) {
if (this.observeList[i] === obj) {
return i
}
i++
}
return -1
}
// 現在のオブザーバーを削除
ObserveList.prototype.removeAt = function (index) {
this.observeList.splice(index, 1);
}
// // オブザーバーのターゲット、観測
function Subject() {
this.observes = new ObserveList();
}
// オブザーバーの追加
Subject.prototype.addObserve = function (observe) {
this.observes.add(observe)
}
//オブザーバのメソッドを削除します。
Subject.prototype.removeObserve = function (observe) {
this.observes.removeAt(this.observes.indexOf(observe, 0))
}
// オブザーバの値が変更されたら、適切なサブスクライバにイベントを通知します。
Subject.prototype.notify = function (context) {
let observeCount = this.observes.count();
for(let i = 0; i < observeCount; i++) {
this.observes.get(i).update(context)
}
}
// オブザーバー
function ObserveGil() {
this.update = function (context) {
console.log('最初のガールフレンドは' + context)
}
}
function ObserveGil1() {
this.update = function (context) {
console.log('2番目のガールフレンドは、' + context)
}
}
function ObserveGil2() {
this.update = function (context) {
console.log('3人目のガールフレンドが' + context)
}
}
// // 特定の用途
let mySubject = new Subject();
mySubject.addObserve(new ObserveGil());
mySubject.addObserve(new ObserveGil1());
mySubject.addObserve(new ObserveGil2());
mySubject.notify('今日は娼婦になる)
// パブリッシング購読者
let publish = {};
(function (myObject) {
// パブリッシング用のメッセージキューを定義する
let topics = {};
// 追加された各購読者に一意の識別子を追加する
let subUid = -1;
// 特定のサブスクリプションを発行する
myObject.publish = function (topic, args) {
if (!topics[topic]) {
return false
}
let subscribers = topics[topic];
let len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, args)
}
return this;
}
// サブスクリプションセンターにサブスクリプションを追加する
myObject.subscribe = function (topic, func) {
// パブリッシュされたメッセージが存在するかどうかを検出し、存在しない場合はストアを作成する。
if (!topics[topic]) {
topics[topic] = []
}
// 一意の識別子を生成する
let token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
})
return token;
}
// 再購読から購読を解除する
myObject.unSubscribe = function (token) {
for (const key in topics) {
if (topics.hasOwnProperty(key)) {
const element = topics[key];
for(let i = 0; i < element.length; i++) {
if (element[i].token === token) {
topics[key].splice(i, 1)
return token
}
}
}
}
return this
}
})(publish);
publish.subscribe('test', () => {console.log('パブリッシュサブスクライバーのメソッドを登録し、実行する')});
publish.publish('test')