Prefácio
Neste capítulo, explicaremos o quinto capítulo da implementação dos cinco principais princípios da linguagem JavaScript sólida, que é o LSP (o princípio da inversão de dependência).
Texto em inglês original: http://freshbrewedcode.com/derekgreeer/2012/01/22/solid-javascript-the-dependency-inversion-principle/
Princípio da inversão de confiança
A descrição do princípio da inversão de dependência é:
A. Os módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.
Módulos de alto nível não devem depender de módulos de baixo nível, ambos devem confiar na abstração
B. As abstrações não devem depender de detalhes. Os detalhes devem depender de abstrações.
Resumo não deve depender dos detalhes, os detalhes devem depender da abstração
A questão mais importante com o princípio da inversão de dependência é garantir que os principais componentes do aplicativo ou estrutura sejam dissociados dos detalhes da implementação do componente subjacente não importante, o que garantirá que as partes mais importantes do programa não sejam afetadas por mudanças e modificações dos componentes de baixo nível.
A primeira parte desse princípio é sobre o acoplamento entre módulos de alto nível e módulos de baixo nível. Na arquitetura da divisão tradicional, os módulos de alto nível (encapsulam a lógica de negócios centrais do programa) sempre dependem de alguns módulos de baixo nível (alguns pontos básicos). Quando o princípio da inversão de dependência é aplicado, o relacionamento é revertido. Ao contrário dos módulos de alto nível que dependem de módulos de baixo nível, a inversão de dependência faz com que os módulos de baixo nível dependam de interfaces definidas em módulos de alto nível. Por exemplo, se você deseja persistir dados para um programa, o design tradicional é que o módulo principal depende da API de um módulo persistente. Após a reconstrução de acordo com o princípio da inversão de dependência, o módulo principal precisa definir uma interface de API persistente e, em seguida, a instância de implementação persistente precisa implementar a interface da API definida pelo módulo principal.
A segunda parte desse princípio descreve a relação correta entre abstração e detalhes. Compreender essa parte é mais útil para entender a linguagem C ++ porque sua aplicabilidade é mais óbvia.
Ao contrário de alguns idiomas estaticamente digitados, o C ++ não fornece um conceito em nível de idioma para definir interfaces. Qual é a relação entre a definição de classe e a implementação da classe? No C ++, as classes são definidas na forma de arquivos de cabeçalho, que definem os métodos e variáveis do membro da classe que o arquivo de origem precisa implementar. Como todas as variáveis e métodos privados são definidos no arquivo de cabeçalho, elas podem ser usadas para abstrair e dissociá -las antes dos detalhes da implementação. O conceito de interface é implementado definindo apenas métodos abstratos (a classe base abstrata em C ++) é usada para implementar classes.
Dip e JavaScript
Como o JavaScript é uma linguagem dinâmica, não há necessidade de abstrair para desacoplar. Portanto, a abstração não deve depender de detalhes. Essa mudança não tem muito impacto no JavaScript, mas os módulos de alto nível não devem depender de módulos de baixo nível, mas têm um grande impacto.
Ao discutir o princípio da inversão de dependência no contexto de idiomas estaticamente tipados, os conceitos de acoplamento incluem semântico e físico. Isso significa que, se um módulo de alto nível depende de um módulo de baixo nível, ele não apenas casal a interface semântica, mas também a interface física definida no módulo subjacente. Em outras palavras, módulos de alto nível devem não apenas ser dissociados da biblioteca de terceiros, mas também de módulos nativos de baixo nível.
Para explicar isso, imagine que um programa .NET pode conter um módulo de alto nível muito útil que se baseia em um módulo persistente de baixo nível. Quando o autor precisa adicionar uma interface semelhante à API de persistência, independentemente de o princípio da inversão de dependência ser usado ou não, os módulos de alto nível não podem ser reutilizados em outros programas antes de implementar a nova interface deste módulo de baixo nível.
No JavaScript, a aplicabilidade do princípio da inversão de dependência é limitada ao acoplamento semântico entre módulos de alto nível e módulos de baixo nível. Por exemplo, o DIP pode adicionar interfaces conforme necessário, em vez de acoplar interfaces implícitas definidas por módulos de baixo nível.
Para entender isso, vamos dar uma olhada no exemplo a seguir:
A cópia do código é a seguinte:
$ .fn.trackmap = function (opções) {
VAR padrão = {
/ * Padrões */
};
opções = $ .extend ({}, padrões, opções);
var mapoptions = {
Centro: novo google.maps.latlng (options.latitude, options.longitude),
Zoom: 12,
MapTypeID: google.maps.maptypeid.roadmap
},
mapa = novo google.maps.map (this [0], mapoPions),
pos = novo google.maps.latlng (options.latitude, options.longitude);
var marker = new google.maps.marker ({
Posição: POS,
Título: Options.title,
Ícone: options.icon
});
Marker.SetMap (MAP);
Options.Feed.Update (função (latitude, longitude) {
Marker.SetMap (NULL);
var newlatlng = new google.maps.latlng (latitude, longitude);
marker.Position = newlatlng;
Marker.SetMap (MAP);
map.setCenter (newlatlng);
});
devolver isso;
};
var updater = (function () {
// Propriedades privadas
retornar {
Atualização: function (retorno de chamada) {
updatemap = retorno de chamada;
}
};
}) ();
$ ("#map_canvas"). trackmap ({
Latitude: 35.044640193770725,
Longitude: -89.98193264007568,
Ícone: 'http://bit.ly/zjngde',
Título: 'Número de rastreamento: 12345',
Feed: Updater
});
No código acima, há uma pequena biblioteca de classes JS que converte uma div em um mapa para exibir as informações de localização rastreadas atualmente. A função TrackMap possui 2 dependências: a API de terceiros do Google Maps e o feed de localização. A responsabilidade do objeto Feed é chamar um retorno de chamada (fornecido na inicialização) quando a posição do ícone é atualizada e passar na latitude e longitude de precisão. A API do Google Maps é usada para renderizar interfaces.
A interface do objeto Feed pode ser baseada na instalação ou não projetada de acordo com os requisitos da função de instalação da faixa. De fato, seu papel é muito simples, com foco em implementações simples e simples e não precisa confiar muito no Google Maps. A semântica do trackmap é acoplada à API do Google Maps. Se você precisar mudar para diferentes provedores de mapas, precisará reescrever a função TrackMap para que ela possa se adaptar a diferentes fornecedores.
Para violar o acoplamento semântico da biblioteca de classes do Google Maps, precisamos reescrever a função de trackmap de design para acoplar uma interface implícita (abstrair a interface do provedor do provedor de mapas). Também precisamos de um objeto de implementação que seja adaptado à API do Google Maps. A seguir, é apresentada a função RATTHMAP REFATORADO:
A cópia do código é a seguinte:
$ .fn.trackmap = function (opções) {
VAR padrão = {
/ * Padrões */
};
opções = $ .extend ({}, padrões, opções);
options.provider.showmap (
isso [0],
options.latitude,
options.longitude,
options.icon,
options.title);
Options.Feed.Update (função (latitude, longitude) {
options.provider.updatemap (latitude, longitude);
});
devolver isso;
};
$ ("#map_canvas"). trackmap ({
Latitude: 35.044640193770725,
Longitude: -89.98193264007568,
Ícone: 'http://bit.ly/zjngde',
Título: 'Número de rastreamento: 12345',
Feed: Updater,
Provedor: trackmap.googleMapsProvider
});
Nesta versão, redesenhamos a função TrackMap e a interface do provedor de mapa necessária e, em seguida, movemos os detalhes da implementação para um componente GoogleMapSprovider separado, que pode ser encapsulado independentemente em um módulo JavaScript separado. Aqui está minha implementação GoogleMapsProvider:
A cópia do código é a seguinte:
trackmap.googleMapsProvider = (function () {
var marcador, mapa;
retornar {
ShowMap: function (elemento, latitude, longitude, ícone, título) {
var mapoptions = {
centro: novo google.maps.latlng (latitude, longitude),
Zoom: 12,
MapTypeID: google.maps.maptypeid.roadmap
},
pos = novo google.maps.latlng (latitude, longitude);
map = new google.maps.map (elemento, mapoptions);
marcador = novo google.maps.marker ({
Posição: POS,
Título: Título,
Ícone: Icon
});
Marker.SetMap (MAP);
},
Updatemap: function (latitude, longitude) {
Marker.SetMap (NULL);
var newlatlng = new google.maps.latlng (latitude, longitude);
marker.Position = newlatlng;
Marker.SetMap (MAP);
map.setCenter (newlatlng);
}
};
}) ();
Depois de fazer as alterações acima, a função TrackMap se tornará muito flexível e não precisará confiar na API do Google Maps. Em vez disso, outros provedores de mapas podem ser substituídos à vontade, ou seja, qualquer provedor de mapas pode ser adaptado de acordo com as necessidades do programa.
Quando a injeção de dependência?
É um pouco não relacionado. De fato, o conceito de injeção de dependência é frequentemente misturado com o princípio da inversão de dependência. Para esclarecer essa diferença, é necessário explicar:
A injeção de dependência é uma forma especial de inversão de controle e a inversão significa como um componente adquire suas dependências. Injeção de dependência significa: a dependência é fornecida ao componente, em vez do componente para obter a dependência, o que significa criar uma instância da dependência, solicitando a dependência através da fábrica e solicitando a dependência através do localizador de serviço ou do próprio componente. O princípio da inversão de dependência e a injeção de dependência estão focados em dependências e são usados para inversão. No entanto, o princípio da inversão de dependência não se concentra em como os componentes adquirem dependências, mas apenas em como os módulos de alto nível são dissociados de módulos de baixo nível. Em certo sentido, o princípio da inversão de dependência é outra forma de inversão de controle. Aqui, a inversão é qual módulo define a interface (definida do nível inferior, inversão para o nível superior).
Resumir
Este é o último artigo dos cinco principais princípios. Nestes 5 artigos, vemos como o sólido é implementado em JavaScript. Diferentes princípios são explicados de diferentes ângulos em JavaScript. (Tio Nota: De fato, acho que, embora seja um pouco inapropriado, de outra perspectiva, os princípios gerais são realmente os mesmos em vários idiomas.)