introduzir
O modo Observer também é chamado de publicação/inscrição. Ele define um relacionamento um para muitos, permitindo que vários objetos de observador ouvam um objeto de tópico ao mesmo tempo. Quando o estado deste tópico mudar, todos os objetos do observador serão notificados, para que possam se atualizar automaticamente.
Benefícios do uso do modo de observador:
1. Suporta a comunicação simples de transmissão e notifica automaticamente todos os objetos inscritos.
2. Depois que a página é carregada, o objeto de destino pode facilmente ter uma correlação dinâmica com o observador, o que aumenta a flexibilidade.
3. A relação de acoplamento abstrata entre o objeto alvo e o observador pode ser expandida e reutilizada separadamente.
Texto (versão 1)
A implementação do padrão de observador no JS é alcançada através de retornos de chamada. Vamos primeiro definir um objeto PubSub, que contém 3 métodos: assinatura, cancelamento de inscrição e publicação.
A cópia do código é a seguinte:
var pubsub = {};
(função (q) {
var tópicos = {}, // Array armazenado pela função de retorno de chamada
subuid = -1;
// Método de publicação
q.publish = function (tópico, args) {
if (! Tópicos [tópico]) {
retornar falso;
}
setTimeout (function () {
var assinantes var = tópicos [tópico],
len = assinantes? assinantes.Length: 0;
while (len--) {
assinantes [len] .func (tópico, args);
}
}, 0);
retornar true;
};
// Método de inscrição
q.subScribe = function (tópico, func) {
if (! Tópicos [tópico]) {
Tópicos [tópico] = [];
}
var token = (++ subuid) .ToString ();
Tópicos [tópico] .push ({
Token: Token,
FUNC: func
});
Token de retorno;
};
// Método de cancelamento de inscrição
Q.UnsubScribe = function (token) {
para (var m em tópicos) {
if (tópicos [m]) {
for (var i = 0, j = tópicos [m] .Length; i <j; i ++) {
if (tópicos [m] [i] .token === token) {
Tópicos [M] .Splice (i, 1);
Token de retorno;
}
}
}
}
retornar falso;
};
} (pubSub));
Como usá -lo é o seguinte:
A cópia do código é a seguinte:
// venha, assine um
pubsub.subscribe ('Exemplo1', função (tópicos, dados) {
console.log (tópicos + ":" + dados);
});
// Aviso de liberação
pubsub.publish ('Exemplo1', 'Hello World!');
pubsub.publish ('exemplo1', ['teste', 'a', 'b', 'c']);
pubsub.publish ('exemplo1', [{'color': 'blue'}, {'text': 'hello'}]);
Que tal? Não é muito bom usar? Mas há um problema com esse método, ou seja, não há como cancelar a inscrição. Se você deseja cancelar a inscrição, deve especificar o nome da inscrição, então vamos para outra versão:
A cópia do código é a seguinte:
// atribui a assinatura a uma variável para cancelar a inscrição
var testSubscription = pubsub.subscribe ('exemplo1', função (tópicos, dados) {
console.log (tópicos + ":" + dados);
});
// Aviso de liberação
pubsub.publish ('Exemplo1', 'Hello World!');
pubsub.publish ('exemplo1', ['teste', 'a', 'b', 'c']);
pubsub.publish ('exemplo1', [{'color': 'blue'}, {'text': 'hello'}]);
// Des -inscrição
setTimeout (function () {
pubsub.unsubscribe (teste de inscrição);
}, 0);
// Publique novamente para verificar se as informações ainda podem ser emitidas
pubsub.publish ('exemplo1', 'Olá novamente! (Isso falhará)');
Versão 2
Também podemos usar as características do protótipo para implementar um padrão de observador, o código é o seguinte:
A cópia do código é a seguinte:
function observer () {
this.fns = [];
}
Observer.prototype = {
Inscreva -se: function (fn) {
this.fns.push (fn);
},
Cancelar inscrição: function (fn) {
this.fns = this.fns.filter (
função (el) {
if (el! == fn) {
retornar el;
}
}
);
},
Atualização: function (o, thisobj) {
var scope = thisObj || janela;
this.fns.foreach (
função (el) {
El.Call (Scope, O);
}
);
}
};
//teste
var o = novo observador;
var f1 = function (dados) {
console.log ('robbin:' + dados + ', trabalhe rapidamente!');
};
var f2 = function (dados) {
Console.log ('Randall:' + Data + ', encontre -o para obter um salário extra!');
};
O.Subscribe (F1);
O.Subscribe (f2);
O.Update ("Tom está de volta!")
// cancela a inscrição para F1
O.Unsubscribe (F1);
// Verifique novamente
O.Update ("Tom está de volta!");
Se a função filtro ou foreach não for encontrada, pode ser porque seu navegador não é novo o suficiente e não suporta novas funções padrão por enquanto. Você pode defini -lo mesmo da seguinte maneira:
A cópia do código é a seguinte:
if (! Array.prototype.foreach) {
Array.prototype.foreach = function (fn, thisobj) {
var scope = thisObj || janela;
for (var i = 0, j = this.length; i <j; ++ i) {
fn.call (escopo, este [i], i, isso);
}
};
}
if (! Array.prototype.Filter) {
Array.prototype.Filter = function (fn, thisobj) {
var scope = thisObj || janela;
var a = [];
for (var i = 0, j = this.length; i <j; ++ i) {
if (! fn.call (escopo, este [i], eu, isso)) {
continuar;
}
a.push (este [i]);
}
retornar a;
};
}
Versão 3
Se você deseja que vários objetos tenham a função da assinatura de publicação do Observer, podemos definir uma função comum e, em seguida, aplicar a função da função ao objeto que requer a função do observador. O código é o seguinte:
A cópia do código é a seguinte:
// Código universal
var observador = {
//subscrição
AddSubScripter: function (retorno de chamada) {
this.subscripters [this.subscripters.length] = retorno de chamada;
},
// Des -inscrição
RemoveSubscripter: function (retorno de chamada) {
for (var i = 0; i <this.subscripters.length; i ++) {
if (this.subscripters [i] === retorno de chamada) {
excluir (this.subscripters [i]);
}
}
},
//liberar
Publicar: function (o quê) {
for (var i = 0; i <this.subscripters.length; i ++) {
if (type of this.subscripters [i] === 'function') {
this.subscripters [i] (o que);
}
}
},
// Faça o objeto o ter função de observador
make: function (o) {
para (var i neste) {
o [i] = este [i];
o.subscripters = [];
}
}
};
Em seguida, inscreva -se em 2 objetos blogueiros e usuário, use o método Observer.Make para fazer com que esses dois objetos tenham funções de observador, o código é o seguinte:
A cópia do código é a seguinte:
var blogger = {
Recomendar: function (id) {
var msg = 'Dudu Post recomendou:' + id;
this.publish (msg);
}
};
Var User = {
Vote: function (id) {
var msg = 'alguém votou! id =' + id;
this.publish (msg);
}
};
Observer.make (blogueiro);
observer.make (usuário);
O método de uso é relativamente simples. Inscreva -se em diferentes funções de retorno de chamada para que você possa se registrar com diferentes objetos de observador (ou vários objetos de observador podem ser registrados ao mesmo tempo):
A cópia do código é a seguinte:
var tom = {
Leia: function (o quê) {
console.log ('Tom viu a seguinte mensagem:' + o que)
}
};
var mm = {
Mostrar: função (o quê) {
Console.log ('MM viu a seguinte mensagem:' + O quê)
}
};
// Inscreva -se
blogger.addsubscripter (tom.read);
blogger.addsubscripter (mm.show);
blogger.recommend (123); // Ligue para publicar
// Des -inscrição
blogger.RemoveSubScruit (mm.show);
blogger.recommend (456); // Ligue para publicar
// Inscrever -se em outro objeto
user.addsubScripter (mm.show);
user.vote (789); // Ligue para publicar
versão jQuery
De acordo com a função On/Off adicionada no JQuery versão 1.7, também podemos definir o observador da versão jQuery:
A cópia do código é a seguinte:
(função ($) {
var o = $ ({});
$ .subScribe = function () {
o.on.Apply (O, argumentos);
};
$ .UnsubScribe = function () {
o.off.Apply (O, argumentos);
};
$ .publish = function () {
O.Trigger.Apply (O, argumentos);
};
} (jQuery));
O método de chamada é mais simples que as três versões acima:
A cópia do código é a seguinte:
// Função de retorno de chamada
identificador de função (e, a, b, c) {
// `e` é um objeto de evento, nenhuma atenção é necessária
console.log (a + b + c);
};
//subscrição
$ .subscribe ("/algum/tópico", manipulação);
//liberar
$ .publish ("/algum/tópico", ["a", "b", "c"]); // saída ABC
$ .Unsubscribe ("/algum/tópico", manipulação); // cancelamento de inscrição
//subscrição
$ .subscribe ("/algum/tópico", função (e, a, b, c) {
console.log (a + b + c);
});
$ .publish ("/algum/tópico", ["a", "b", "c"]); // saída ABC
// cancelamento de inscrição (cancelar a inscrição usa o nome/algum nome/tópico, não a função de retorno de chamada, que é diferente do exemplo da versão 1
$ .Unsubscribe ("/algum/tópico");
Pode -se observar que sua assinatura e cancelamento de inscrição usam nomes de strings, não nomes de funções de retorno de chamada, portanto, mesmo que a função anônima recebida seja aprovada, podemos cancelar a inscrição.
Resumir
O uso dos observadores é: quando um objeto muda para alterar outros objetos ao mesmo tempo e não sabe quantos objetos precisam ser alterados, deve considerar o uso do modo Observer.
No geral, o que o padrão de observador faz é decompar, fazendo com que os dois lados do acoplamento dependam da abstração em vez de concreto. Isso possibilita que as alterações uma da outra não afetem as mudanças do outro lado.