Wednesday 28 March 2018

Inversão do padrão de estratégia de controle


Introdução à Inversão de Controle e Injeção de Dependência com a Mola.
Última modificação: 25 de fevereiro de 2018.
Acabei de anunciar os novos módulos do Spring 5 em REST With Spring:
1. Visão Geral.
Neste artigo, apresentaremos os conceitos de IoC (Inversão de Controle) e DI (Injeção de Dependência) e, em seguida, veremos como eles são implementados na estrutura do Spring.
2. O que é inversão de controle?
Inversão de Controle é um princípio em engenharia de software pelo qual o controle de objetos ou partes de um programa é transferido para um contêiner ou estrutura. É mais frequentemente usado no contexto de programação orientada a objetos.
Em contraste com a programação tradicional, na qual nosso código personalizado faz chamadas para uma biblioteca, o IoC permite que uma estrutura assuma o controle do fluxo de um programa e faça chamadas para nosso código personalizado. Para permitir isso, os frameworks usam abstrações com comportamento adicional incorporado. Se quisermos adicionar nosso próprio comportamento, precisamos estender as classes do framework ou fazer o plugin de nossas próprias classes.
As vantagens desta arquitetura são:
desacoplar a execução de uma tarefa de sua implementação, tornando mais fácil alternar entre diferentes implementações maior modularidade de um programa maior facilidade em testar um programa, isolando um componente ou zombando de suas dependências e permitindo que os componentes se comuniquem através de contratos.
A inversão de controle pode ser alcançada através de vários mecanismos, tais como: Padrão de design de estratégia, Padrão de localizador de serviço, Padrão de fábrica e Injeção de dependência (DI).
Nós vamos ver a DI em seguida.
3. O que é Injeção de Dependência?
Injeção de dependência é um padrão através do qual implementar o IoC, onde o controle que está sendo invertido é a configuração das dependências do objeto.
O ato de conectar objetos com outros objetos, ou "injetando & # 8221; objetos em outros objetos, é feito por um montador e não pelos próprios objetos.
Veja como você criaria uma dependência de objeto na programação tradicional:
No exemplo acima, precisamos instanciar uma implementação da interface Item dentro da própria classe Store.
Usando DI, podemos reescrever o exemplo sem especificar a implementação do Item que queremos:
Nas próximas seções, veremos como podemos fornecer a implementação do item por meio de metadados.
Tanto o IoC quanto o DI são conceitos simples, mas têm profundas implicações na forma como estruturamos nossos sistemas, então eles valem bem a compreensão.
4. O Contêiner IoC da Primavera.
Um contêiner IoC é uma característica comum de estruturas que implementam o IoC.
Na estrutura Spring, o contêiner IoC é representado pela interface ApplicationContext. O contêiner Spring é responsável por instanciar, configurar e montar objetos conhecidos como beans, além de gerenciar seu ciclo de vida.
A estrutura Spring fornece várias implementações da interface ApplicationContext - ClassPathXmlApplicationContext e FileSystemXmlApplicationContext para aplicativos independentes e WebApplicationContext para aplicativos da Web.
Para montar beans, o contêiner usa metadados de configuração, que podem estar na forma de configuração XML ou anotações.
Aqui está uma forma de instanciar manualmente um contêiner:
5. Injeção de Dependência na Primavera.
Para definir o atributo de item no exemplo acima, podemos usar metadados. Em seguida, o contêiner lerá esses metadados e os usará para montar beans em tempo de execução.
A Injeção de Dependência na Mola pode ser feita através de construtores, setters ou campos.
5.1. Injeção de Dependência Baseada em Construtor.
No caso de injeção de dependência baseada em construtor, o contêiner invocará um construtor com argumentos cada representando uma dependência que desejamos definir.
Spring resolve cada argumento principalmente por tipo, seguido pelo nome do atributo e pelo índice para desambiguação. Vamos ver a configuração de um bean e suas dependências usando anotações:
A anotação @Configuration indica que a classe é uma fonte de definições de beans. Além disso, podemos adicioná-lo a várias classes de configuração.
A anotação @Bean é usada em um método para definir um bean. Se não especificarmos um nome personalizado, o nome do bean será padronizado para o nome do método.
Para um bean com o escopo singleton padrão, o Spring primeiro verifica se uma instância armazenada em cache do bean já existe e somente cria um novo caso ele não exista. Se estivermos usando o escopo de protótipo, o contêiner retornará uma nova instância de bean para cada chamada de método.
Outra maneira de criar a configuração dos beans é através da configuração XML:
5.2. Injeção de Dependência Baseada em Setter.
Para o DI baseado em setter, o contêiner chamará os métodos setter de nossa classe, após invocar um construtor sem argumento ou um método factory estático sem argumento para instanciar o bean. Vamos criar essa configuração usando anotações:
Também podemos usar XML para a mesma configuração de beans:
Tipos de injeção baseados em construtor e baseados em setter podem ser combinados para o mesmo bean. A documentação do Spring recomenda o uso de injeção baseada em construtor para dependências obrigatórias e injeção baseada em setter para as opcionais.
5.3. Injeção de Dependência Baseada em Campo.
No caso de DI baseada em campo, podemos injetar as dependências marcando-as com uma anotação @Autowired:
Ao construir o objeto Store, se não houver um método de construtor ou setter para injetar o bean Item, o contêiner usará reflection para injetar Item na Store.
Também podemos conseguir isso usando a configuração XML.
Essa abordagem pode parecer mais simples e mais limpa, mas não é recomendável usá-la porque tem alguns inconvenientes, como:
Esse método usa a reflexão para injetar as dependências, o que é mais caro do que a injeção baseada em construtor ou baseada em setter. É realmente fácil continuar adicionando várias dependências usando essa abordagem. Se você estivesse usando a injeção de construtor com vários argumentos, isso nos faria pensar que a classe faz mais do que uma coisa que pode violar o Princípio de Responsabilidade Única.
Mais informações sobre a anotação @Autowired podem ser encontradas no artigo Fiação na primavera.
5.4. Dependências de Autowiring.
A fiação permite que o contêiner Spring resolva automaticamente as dependências entre os beans de colaboração, inspecionando os beans que foram definidos.
Existem quatro modos de autowiring um bean usando uma configuração XML:
não: o valor padrão & # 8211; isso significa que não é utilizada autoabastagem para o bean e temos que nomear explicitamente as dependências byName: autowiring é feita com base no nome da propriedade, portanto, o Spring procurará um bean com o mesmo nome da propriedade que precisa ser definida por Type : semelhante ao autowiring byName, baseado apenas no tipo da propriedade. Isso significa que o Spring procurará um bean com o mesmo tipo de propriedade para definir. Se houver mais de um bean desse tipo, o framework lançará uma exceção. construtor: o autowiring é feito com base nos argumentos do construtor, o que significa que o Spring procurará beans com o mesmo tipo que os argumentos do construtor.
Por exemplo, vamos autowire o item1 bean definido acima por tipo no bean de loja:
Também podemos injetar beans usando a anotação @Autowired para autowiring por tipo:
Se houver mais de um bean do mesmo tipo, podemos usar a anotação @Qualifier para fazer referência a um bean pelo nome:
Agora, vamos criar os beans de papel por tipo através da configuração XML:
Em seguida, vamos injetar um item nomeado de bean na propriedade de item do bean de loja por nome através de XML:
Também podemos substituir o autowiring definindo dependências explicitamente através de argumentos ou setters de construtor.
5.5. Feijão Inicializado Preguiçoso.
Por padrão, o contêiner cria e configura todos os beans singleton durante a inicialização. Para evitar isso, você pode usar o atributo lazy-init com o valor true na configuração do bean:
Como consequência, o bean item1 será inicializado apenas quando for solicitado pela primeira vez e não na inicialização. A vantagem disso é o tempo de inicialização mais rápido, mas a desvantagem é que os erros de configuração podem ser descobertos somente depois que o bean é solicitado, o que pode levar várias horas ou até mesmo dias após o aplicativo já estar em execução.
6. Conclusão.
Neste artigo, apresentamos os conceitos de inversão de controle e injeção de dependência e os exemplificamos no framework Spring.
Você pode ler mais sobre esses conceitos nos artigos de Martin Fowler:
E você pode aprender mais sobre as implementações Spring de IoC e DI na Documentação de Referência do Spring Framework.

Inversão do padrão de estratégia de controle
Injeção de dependência refere-se ao padrão de dizer a uma classe quais serão suas dependências, em vez de exigir que a classe saiba onde encontrar todas as suas dependências.
Então, por exemplo, você vai a partir disso:
para algo assim:
Isso reduz o acoplamento no código, o que é especialmente útil se você quiser testar o UserFetcher. Agora, em vez de o UserFetcher estar sempre sendo executado em um banco de dados localizado em 10.167.1.25, você pode passar um DbConnection para um banco de dados de teste. Ou, ainda mais útil em um teste rápido, você pode passar em uma implementação ou subclasse de DbConnection que nem sequer se conecta a um banco de dados, apenas descarta os pedidos!
No entanto, esse tipo de injeção de dependência primitiva dificulta o cabeamento (fornecendo um objeto com suas dependências), porque você substituiu o acesso à dependência usando uma variável global (ou um objeto instanciado localmente) passando a dependência por todo o gráfico de objeto .
Pense em um caso em que UserFetcher é uma dependência do AccountManager, que é uma dependência do AdminConsole. Em seguida, o AdminConsole precisa passar a instância do DbConnection para o AccountManager, e o AccountManager precisa passá-la para o UserFetcher. mesmo que nem o AdminConsole nem o AccountManager precisem usar o DbConnection diretamente!
Uma inversão do contêiner de controle (Spring, Guice, etc) tem como objetivo facilitar a injeção de dependência, conectando automaticamente (fornecendo) as dependências. Para fazer isso, você diz ao seu contêiner IoC uma vez como fornecer um objeto (no Spring, isso é chamado de bean) e sempre que outro objeto solicitar essa dependência, ele será fornecido pelo contêiner.
Então, nosso último exemplo pode ser assim com Guice, se usássemos injeção de construtor:
E nós temos que configurar o contêiner IoC. Em Guice isso é feito através de uma implementação do Módulo; no Spring, você configura um contexto de aplicativo, geralmente por meio de XML.
Agora, quando o UserFetcher é construído por Guice ou Spring, o DbConnection é fornecido automaticamente.
Guice tem um artigo Wiki realmente bom sobre a motivação por trás da injeção de dependência, e ainda usando um contêiner IoC. Vale a pena ler todo o caminho.
O padrão de estratégia é apenas um caso especial de injeção de dependência, em que você injeta lógica em vez de um objeto (mesmo que, em Java, a lógica seja encapsulada em um objeto). É uma maneira de desvincular a lógica comercial independente.
Por exemplo, você pode ter um código como este:
Mas e se você quisesse estender esse código para uma nova jurisdição, com um esquema diferente de imposto sobre vendas? Você poderia injetar a lógica para calcular o imposto, assim:

Inversão de Contêineres de Controle e o padrão de Injeção de Dependência.
Na comunidade Java, houve uma onda de contêineres leves que ajudam a montar componentes de diferentes projetos em um aplicativo coeso. Subjacente a esses contêineres está um padrão comum de como eles realizam a fiação, um conceito que eles se referem sob o nome muito genérico de "Inversão de Controle". Neste artigo, vou investigar como esse padrão funciona, sob o nome mais específico de "Injeção de Dependência", e compará-lo com a alternativa do Service Locator. A escolha entre eles é menos importante que o princípio de separar configuração de uso.
23 de janeiro de 2004.
Uma das coisas divertidas sobre o mundo corporativo de Java é a enorme quantidade de atividades na construção de alternativas para as tecnologias J2EE tradicionais, muitas delas acontecendo em código aberto. Muito disso é uma reação à complexidade pesada no mundo mainstream do J2EE, mas grande parte dele também está explorando alternativas e criando ideias criativas. Um problema comum é lidar com diferentes elementos: como você se encaixa nessa arquitetura de controlador de web com esse suporte de interface de banco de dados quando eles foram criados por equipes diferentes com pouco conhecimento um do outro. Vários frameworks tentaram resolver esse problema, e vários estão se ramificando para fornecer uma capacidade geral de montar componentes de diferentes camadas. Eles são geralmente chamados de contêineres leves; os exemplos incluem PicoContainer e Spring.
Subjacente a esses contêineres estão vários princípios de design interessantes, coisas que vão além desses contêineres específicos e, na verdade, da plataforma Java. Aqui eu quero começar a explorar alguns desses princípios. Os exemplos que uso são em Java, mas como a maioria dos meus artigos, os princípios são igualmente aplicáveis ​​a outros ambientes OO, particularmente.
Componentes e Serviços.
O tópico dos elementos de ligação juntos me arrasta quase imediatamente para os problemas de terminologia complicados que envolvem os termos serviço e componente. Você encontra artigos longos e contraditórios sobre a definição dessas coisas com facilidade. Para os meus propósitos aqui estão meus usos atuais desses termos sobrecarregados.
Eu uso componente para significar uma série de software que se destina a ser usado, sem alteração, por um aplicativo que está fora do controle dos escritores do componente. Por 'sem alteração', quero dizer que o aplicativo em uso não altera o código-fonte dos componentes, embora eles possam alterar o comportamento do componente estendendo-o de maneiras permitidas pelos gravadores de componentes.
Um serviço é semelhante a um componente em que é usado por aplicativos estrangeiros. A principal diferença é que espero que um componente seja usado localmente (pense em arquivo jar, assembly, dll ou uma importação de origem). Um serviço será usado remotamente por meio de alguma interface remota, síncrona ou assíncrona (por exemplo, serviço da web, sistema de mensagens, RPC ou soquete).
Eu uso principalmente o serviço neste artigo, mas muito da mesma lógica pode ser aplicada a componentes locais também. Na verdade, muitas vezes você precisa de algum tipo de estrutura de componente local para acessar facilmente um serviço remoto. Mas escrever "componente ou serviço" é cansativo para ler e escrever, e os serviços estão muito mais na moda no momento.
Um exemplo ingênuo.
Para ajudar a tornar tudo isso mais concreto, vou usar um exemplo em execução para falar sobre tudo isso. Como todos os meus exemplos, é um desses exemplos super simples; pequeno o suficiente para ser irreal, mas espero o suficiente para você visualizar o que está acontecendo sem cair no pântano de um exemplo real.
Neste exemplo, estou escrevendo um componente que fornece uma lista de filmes dirigidos por um determinado diretor. Esta função incrivelmente útil é implementada por um único método.
A implementação desta função é ingênua ao extremo, ela pede a um objeto localizador (que nós vamos chegar em um momento) para retornar todos os filmes que ele conhece. Em seguida, ele apenas procura por essa lista para retornar aquelas dirigidas por um diretor em particular. Essa particular peça de ingenuidade eu não vou consertar, já que é apenas o andaime para o ponto real deste artigo.
O ponto real deste artigo é este objeto buscador, ou particularmente como nós conectamos o objeto lister com um objeto localizador particular. A razão pela qual isso é interessante é que eu quero que o meu maravilhoso método moviesDirectedBy seja completamente independente de como todos os filmes estão sendo armazenados. Portanto, todo o método se refere a um localizador, e tudo que o localizador faz é saber como responder ao método findAll. Eu posso trazer isso definindo uma interface para o localizador.
Agora tudo isso está muito bem dissociado, mas em algum momento eu tenho que criar uma classe concreta para criar os filmes. Neste caso, eu coloquei o código para isso no construtor da minha aula de lister.
O nome da classe de implementação vem do fato de que estou obtendo minha lista de um arquivo de texto delimitado por dois pontos. Vou poupar os detalhes, afinal o ponto é que há alguma implementação.
Agora, se eu estou usando essa classe apenas para mim, tudo isso é bom e elegante. Mas o que acontece quando meus amigos estão sobrecarregados pelo desejo por essa funcionalidade maravilhosa e gostariam de uma cópia do meu programa? Se eles também armazenam suas listagens de filmes em um arquivo de texto delimitado por dois pontos chamado "movies1.txt", então tudo é maravilhoso. Se eles tiverem um nome diferente para o arquivo de filmes, será fácil colocar o nome do arquivo em um arquivo de propriedades. Mas e se eles tiverem uma forma completamente diferente de armazenar sua listagem de filmes: um banco de dados SQL, um arquivo XML, um serviço da Web ou apenas outro formato de arquivo de texto? Neste caso, precisamos de uma classe diferente para pegar esses dados. Agora, porque eu defini uma interface do MovieFinder, isso não alterará o meu método moviesDirectedBy. Mas ainda preciso ter uma maneira de implementar uma instância da implementação do localizador correto.
Figura 1: As dependências usando uma criação simples na classe de listagem.
A Figura 1 mostra as dependências para essa situação. A classe MovieLister depende da interface do MovieFinder e da implementação. Nós preferiríamos que dependesse apenas da interface, mas como podemos criar uma instância para trabalhar?
No meu livro P de EAA, nós descrevemos esta situação como um Plugin. A classe de implementação para o localizador não está vinculada ao programa em tempo de compilação, já que não sei o que meus amigos vão usar. Em vez disso, queremos que meu lister trabalhe com qualquer implementação e, para que a implementação seja conectada em algum ponto posterior, fora de minhas mãos. O problema é como posso fazer esse link para que minha classe de lister seja ignorante da classe de implementação, mas ainda possa falar com uma instância para fazer seu trabalho.
Expandindo isso em um sistema real, podemos ter dezenas desses serviços e componentes. Em cada caso, podemos abstrair nosso uso desses componentes conversando com eles através de uma interface (e usando um adaptador se o componente não for projetado com uma interface em mente). Mas, se quisermos implantar esse sistema de maneiras diferentes, precisamos usar plug-ins para lidar com a interação com esses serviços, para que possamos usar diferentes implementações em diferentes implantações.
Então, o problema central é como montar esses plugins em um aplicativo? Este é um dos principais problemas que esta nova geração de contêineres leves enfrenta e, universalmente, todos fazem isso usando a Inversion of Control.
Inversão de controle.
Quando esses contêineres falam sobre como eles são tão úteis porque implementam a "Inversão do Controle", acabo intrigado. A inversão de controle é uma característica comum dos frameworks, portanto, dizer que esses contêineres leves são especiais porque eles usam inversão de controle é como dizer que meu carro é especial porque tem rodas.
A questão é: "que aspecto de controle eles estão invertendo?" Quando comecei a inversão de controle, estava no controle principal de uma interface de usuário. Interfaces de usuário iniciais eram controladas pelo programa aplicativo. Você teria uma sequência de comandos como "Digite o nome", "insira o endereço"; seu programa conduziria os prompts e pegaria uma resposta para cada um. Com UIs gráficas (ou mesmo baseadas em telas), a estrutura da interface do usuário conteria esse loop principal e, em vez disso, o programa forneceria manipuladores de eventos para os vários campos da tela. O controle principal do programa foi invertido, afastado de você para o quadro.
Para essa nova geração de contêineres, a inversão é sobre como eles pesquisam uma implementação de plug-in. Em meu ingênuo exemplo, o lister procurou a implementação do localizador, instanciando-a diretamente. Isso impede que o localizador seja um plugin. A abordagem usada por esses contêineres é garantir que qualquer usuário de um plug-in siga alguma convenção que permita que um módulo assembler separado injete a implementação na lista.
Como resultado, acho que precisamos de um nome mais específico para esse padrão. Inversão de Controle é um termo muito genérico e, portanto, as pessoas acham confuso. Como resultado de muita discussão com vários defensores do IoC, decidimos o nome Injeção de Dependência.
Vou começar falando sobre as várias formas de injeção de dependência, mas vou apontar agora que essa não é a única maneira de remover a dependência da classe de aplicativo para a implementação do plug-in. O outro padrão que você pode usar para fazer isso é Service Locator, e eu vou discutir isso depois que eu terminar de explicar a Injeção de Dependência.
Formas de Injeção de Dependência.
A ideia básica da Injeção de Dependência é ter um objeto separado, um montador, que preencha um campo na classe de listagem com uma implementação apropriada para a interface do localizador, resultando em um diagrama de dependência ao longo das linhas da Figura 2.
Figura 2: As dependências de um Injector de Dependência.
Existem três estilos principais de injeção de dependência. Os nomes que estou usando para eles são Injeção de Construtor, Injeção de Setter e Injeção de Interface. Se você ler sobre essas coisas nas discussões atuais sobre Inversão de Controle, ouvirá essas chamadas como IoC do tipo 1 (injeção de interface), tipo IoC (injeção de setter) tipo 2 e IoC tipo 3 (injeção de construtor). Eu acho nomes numéricos bastante difíceis de lembrar, e é por isso que usei os nomes que tenho aqui.
Injeção de Construtor com PicoContainer.
Começarei mostrando como essa injeção é feita usando um contêiner leve chamado PicoContainer. Estou começando aqui principalmente porque vários dos meus colegas da ThoughtWorks são muito ativos no desenvolvimento do PicoContainer (sim, é uma espécie de nepotismo corporativo).
O PicoContainer usa um construtor para decidir como injetar uma implementação do localizador na classe de listagem. Para que isso funcione, a classe lister do filme precisa declarar um construtor que inclui tudo o que precisa ser injetado.
O localizador em si também será gerenciado pelo contêiner pico e, como tal, terá o nome do arquivo de texto injetado nele pelo contêiner.
O contêiner pico precisa ser informado sobre qual classe de implementação associar a cada interface e qual string injetar no localizador.
Esse código de configuração é normalmente configurado em uma classe diferente. Para nosso exemplo, cada amigo que usa meu lister pode escrever o código de configuração apropriado em alguma classe de configuração própria. É claro que é comum manter esse tipo de informação de configuração em arquivos de configuração separados. Você pode escrever uma classe para ler um arquivo de configuração e configurar o contêiner adequadamente. Embora o PicoContainer não contenha essa funcionalidade, existe um projeto relacionado, chamado NanoContainer, que fornece os wrappers apropriados para permitir que você tenha arquivos de configuração XML. Tal nano contêiner irá analisar o XML e, em seguida, configurar um recipiente pico subjacente. A filosofia do projeto é separar o formato do arquivo de configuração do mecanismo subjacente.
Para usar o contêiner, você escreve um código como este.
Embora neste exemplo eu tenha usado injeção de construtor, o PicoContainer também suporta injeção de setter, embora seus desenvolvedores prefiram a injeção de construtor.
Injeção Setter com a primavera.
O framework Spring é uma estrutura abrangente para o desenvolvimento Java corporativo. Inclui camadas de abstração para transações, estruturas de persistência, desenvolvimento de aplicativos da Web e JDBC. Como o PicoContainer, ele suporta injeção de construtor e setter, mas seus desenvolvedores tendem a preferir injeção de setter - o que o torna uma escolha apropriada para este exemplo.
Para que meu filme lister aceite a injeção, defino um método de configuração para esse serviço.
Da mesma forma eu defino um setter para o nome do arquivo.
O terceiro passo é configurar a configuração dos arquivos. Spring suporta configuração através de arquivos XML e também através de código, mas XML é a maneira esperada de fazê-lo.
O teste então se parece com isso.
Injeção de interface.
A terceira técnica de injeção é definir e usar interfaces para a injeção. Avalon é um exemplo de uma estrutura que usa essa técnica em locais. Falarei um pouco mais sobre isso depois, mas neste caso vou usá-lo com algum código de amostra simples.
Com essa técnica, começo definindo uma interface que utilizarei para executar a injeção. Aqui está a interface para injetar um localizador de filme em um objeto.
Essa interface seria definida por quem fornecer a interface do MovieFinder. Ele precisa ser implementado por qualquer classe que queira usar um localizador, como o lister.
class MovieLister implementa InjectFinder.
Eu uso uma abordagem semelhante para injetar o nome do arquivo na implementação do localizador.
A classe ColonMovieFinder implementa o MovieFinder, InjectFinderFilename.
Então, como de costume, eu preciso de algum código de configuração para ligar as implementações. Para simplificar vou fazer isso em código.
Esta configuração tem dois estágios, registrando componentes através de chaves de pesquisa é bastante semelhante aos outros exemplos.
Um novo passo é registrar os injetores que injetarão os componentes dependentes. Cada interface de injeção precisa de algum código para injetar o objeto dependente. Aqui eu faço isso registrando objetos injetores com o contêiner. Cada objeto injetor implementa a interface do injetor.
Quando o dependente é uma classe escrita para este contêiner, faz sentido que o componente implemente a interface do injetor em si, como faço aqui com o localizador de filme. Para classes genéricas, como a string, eu uso uma classe interna dentro do código de configuração.
classe ColonMovieFinder implementa Injector.
Os testes, em seguida, usam o contêiner.
O contêiner usa as interfaces de injeção declaradas para descobrir as dependências e os injetores para injetar os dependentes corretos. (A implementação do container específico que fiz aqui não é importante para a técnica, e não mostrarei porque você só riria.)
Usando um localizador de serviço.
O principal benefício de um Injetor de Dependência é que ele remove a dependência que a classe MovieLister tem na implementação concreta do MovieFinder. Isso permite que eu forneça informações a amigos e que eles implementem uma implementação adequada para seu próprio ambiente. Injeção não é a única maneira de quebrar essa dependência, outra é usar um localizador de serviço.
A idéia básica por trás de um localizador de serviços é ter um objeto que saiba como obter todos os serviços que um aplicativo pode precisar. Portanto, um localizador de serviço para esse aplicativo teria um método que retornasse um localizador de filme quando fosse necessário. Claro que isso apenas muda o fardo um pouco, ainda temos que colocar o localizador no lister, resultando nas dependências da Figura 3.
Figura 3: As dependências de um Service Locator.
Nesse caso, usarei o ServiceLocator como um registro singleton. O lister pode então usar isso para obter o localizador quando ele é instanciado.
Assim como na abordagem de injeção, temos que configurar o localizador de serviço. Aqui estou fazendo isso em código, mas não é difícil usar um mecanismo que leia os dados apropriados de um arquivo de configuração.
Aqui está o código de teste.
Eu sempre ouvi a reclamação de que esses tipos de localizadores de serviço são uma coisa ruim porque eles não são testáveis ​​porque você não pode substituir implementações para eles. Certamente você pode projetá-los mal para entrar nesse tipo de problema, mas você não precisa fazê-lo. Neste caso, a instância do localizador de serviços é apenas um simples detentor de dados. Eu posso criar facilmente o localizador com implementações de teste dos meus serviços.
Para um localizador mais sofisticado, posso subclassificar o localizador de serviços e passar essa subclasse para a variável de classe do registro. Eu posso alterar os métodos estáticos para chamar um método na instância em vez de acessar diretamente as variáveis ​​de instância. Posso fornecer localizadores específicos thread & # x2013; usando armazenamento específico thread & # x2013; Tudo isso pode ser feito sem alterar os clientes do localizador de serviços.
Uma maneira de pensar nisso é que o localizador de serviço é um registro e não um singleton. Um singleton fornece uma maneira simples de implementar um registro, mas essa decisão de implementação é facilmente alterada.
Usando uma interface Segregada para o Localizador.
Um dos problemas com a abordagem simples acima, é que o MovieLister é dependente da classe do localizador de serviço completo, mesmo que ele use apenas um serviço. Podemos reduzir isso usando uma interface de função. Dessa forma, em vez de usar a interface do localizador de serviço completo, o lister pode declarar apenas o pouco da interface de que precisa.
Nessa situação, o provedor do lister também forneceria uma interface de localização que precisa para obter o localizador.
O localizador precisa implementar essa interface para fornecer acesso a um localizador.
Você notará que, como queremos usar uma interface, não podemos mais acessar os serviços por meio de métodos estáticos. Temos que usar a classe para obter uma instância do localizador e usá-la para obter o que precisamos.
Um localizador de serviço dinâmico.
O exemplo acima foi estático, em que a classe de localizador de serviço tem métodos para cada um dos serviços que você precisa. Esta não é a única maneira de fazer isso, você também pode criar um localizador de serviço dinâmico que lhe permita armazenar qualquer serviço que você precise e fazer suas escolhas em tempo de execução.
Nesse caso, o localizador de serviço usa um mapa em vez de campos para cada um dos serviços e fornece métodos genéricos para obter e carregar serviços.
A configuração envolve o carregamento de um serviço com uma chave apropriada.
Eu uso o serviço usando a mesma string de chave.
No geral, eu não gosto dessa abordagem. Embora seja certamente flexível, não é muito explícito. A única maneira de descobrir como acessar um serviço é por meio de chaves textuais. Eu prefiro métodos explícitos porque é mais fácil encontrar onde eles estão olhando as definições da interface.
Usando um localizador e uma injeção com Avalon.
Injeção de dependência e um localizador de serviço não são necessariamente conceitos mutuamente exclusivos. Um bom exemplo de usar os dois juntos é o framework Avalon. A Avalon usa um localizador de serviços, mas usa a injeção para informar aos componentes onde encontrar o localizador.
Berin Loritsch me enviou uma versão simples do meu exemplo de corrida usando o Avalon.
O método de serviço é um exemplo de injeção de interface, permitindo que o contêiner injete um gerenciador de serviços no MyMovieLister. O gerente de serviços é um exemplo de um localizador de serviços. Neste exemplo, o lister não armazena o gerenciador em um campo, em vez disso, ele imediatamente o utiliza para procurar o localizador, que ele armazena.
Decidindo qual opção usar.
Até agora, concentrei-me em explicar como vejo esses padrões e suas variações. Agora posso começar a falar sobre seus prós e contras para ajudar a descobrir quais usar e quando.
Localizador de Serviço vs Injeção de Dependência.
A escolha fundamental é entre o Service Locator e a Dependency Injection. O primeiro ponto é que ambas as implementações fornecem o desacoplamento fundamental que está faltando no exemplo ingênuo - em ambos os casos, o código do aplicativo é independente da implementação concreta da interface de serviço. A diferença importante entre os dois padrões é sobre como essa implementação é fornecida para a classe de aplicativo. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.
Inversion of control is a common feature of frameworks, but it's something that comes at a price. It tends to be hard to understand and leads to problems when you are trying to debug. So on the whole I prefer to avoid it unless I need it. This isn't to say it's a bad thing, just that I think it needs to justify itself over the more straightforward alternative.
The key difference is that with a Service Locator every user of a service has a dependency to the locator. The locator can hide dependencies to other implementations, but you do need to see the locator. So the decision between locator and injector depends on whether that dependency is a problem.
Using dependency injection can help make it easier to see what the component dependencies are. With dependency injector you can just look at the injection mechanism, such as the constructor, and see the dependencies. With the service locator you have to search the source code for calls to the locator. Modern IDEs with a find references feature make this easier, but it's still not as easy as looking at the constructor or setting methods.
A lot of this depends on the nature of the user of the service. If you are building an application with various classes that use a service, then a dependency from the application classes to the locator isn't a big deal. In my example of giving a Movie Lister to my friends, then using a service locator works quite well. All they need to do is to configure the locator to hook in the right service implementations, either through some configuration code or through a configuration file. In this kind of scenario I don't see the injector's inversion as providing anything compelling.
The difference comes if the lister is a component that I'm providing to an application that other people are writing. In this case I don't know much about the APIs of the service locators that my customers are going to use. Each customer might have their own incompatible service locators. I can get around some of this by using the segregated interface. Each customer can write an adapter that matches my interface to their locator, but in any case I still need to see the first locator to lookup my specific interface. And once the adapter appears then the simplicity of the direct connection to a locator is beginning to slip.
Since with an injector you don't have a dependency from a component to the injector, the component cannot obtain further services from the injector once it's been configured.
A common reason people give for preferring dependency injection is that it makes testing easier. The point here is that to do testing, you need to easily replace real service implementations with stubs or mocks. However there is really no difference here between dependency injection and service locator: both are very amenable to stubbing. I suspect this observation comes from projects where people don't make the effort to ensure that their service locator can be easily substituted. This is where continual testing helps, if you can't easily stub services for testing, then this implies a serious problem with your design.
Of course the testing problem is exacerbated by component environments that are very intrusive, such as Java's EJB framework. My view is that these kinds of frameworks should minimize their impact upon application code, and particularly should not do things that slow down the edit-execute cycle. Using plugins to substitute heavyweight components does a lot to help this process, which is vital for practices such as Test Driven Development.
So the primary issue is for people who are writing code that expects to be used in applications outside of the control of the writer. In these cases even a minimal assumption about a Service Locator is a problem.
Constructor versus Setter Injection.
For service combination, you always have to have some convention in order to wire things together. The advantage of injection is primarily that it requires very simple conventions - at least for the constructor and setter injections. You don't have to do anything odd in your component and it's fairly straightforward for an injector to get everything configured.
Interface injection is more invasive since you have to write a lot of interfaces to get things all sorted out. For a small set of interfaces required by the container, such as in Avalon's approach, this isn't too bad. But it's a lot of work for assembling components and dependencies, which is why the current crop of lightweight containers go with setter and constructor injection.
The choice between setter and constructor injection is interesting as it mirrors a more general issue with object-oriented programming - should you fill fields in a constructor or with setters.
My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns : Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations.
Another advantage with constructor initialization is that it allows you to clearly hide any fields that are immutable by simply not providing a setter. I think this is important - if something shouldn't change then the lack of a setter communicates this very well. If you use setters for initialization, then this can become a pain. (Indeed in these situations I prefer to avoid the usual setting convention, I'd prefer a method like initFoo , to stress that it's something you should only do at birth.)
But with any situation there are exceptions. If you have a lot of constructor parameters things can look messy, particularly in languages without keyword parameters. It's true that a long constructor is often a sign of an over-busy object that should be split, but there are cases when that's what you need.
If you have multiple ways to construct a valid object, it can be hard to show this through constructors, since constructors can only vary on the number and type of parameters. This is when Factory Methods come into play, these can use a combination of private constructors and setters to implement their work. The problem with classic Factory Methods for components assembly is that they are usually seen as static methods, and you can't have those on interfaces. You can make a factory class, but then that just becomes another service instance. A factory service is often a good tactic, but you still have to instantiate the factory using one of the techniques here.
Constructors also suffer if you have simple parameters such as strings. With setter injection you can give each setter a name to indicate what the string is supposed to do. With constructors you are just relying on the position, which is harder to follow.
If you have multiple constructors and inheritance, then things can get particularly awkward. In order to initialize everything you have to provide constructors to forward to each superclass constructor, while also adding you own arguments. This can lead to an even bigger explosion of constructors.
Despite the disadvantages my preference is to start with constructor injection, but be ready to switch to setter injection as soon as the problems I've outlined above start to become a problem.
This issue has led to a lot of debate between the various teams who provide dependency injectors as part of their frameworks. However it seems that most people who build these frameworks have realized that it's important to support both mechanisms, even if there's a preference for one of them.
Code or configuration files.
A separate but often conflated issue is whether to use configuration files or code on an API to wire up services. For most applications that are likely to be deployed in many places, a separate configuration file usually makes most sense. Almost all the time this will be an XML file, and this makes sense. However there are cases where it's easier to use program code to do the assembly. One case is where you have a simple application that's not got a lot of deployment variation. In this case a bit of code can be clearer than a separate XML file.
A contrasting case is where the assembly is quite complex, involving conditional steps. Once you start getting close to programming language then XML starts breaking down and it's better to use a real language that has all the syntax to write a clear program. You then write a builder class that does the assembly. If you have distinct builder scenarios you can provide several builder classes and use a simple configuration file to select between them.
I often think that people are over-eager to define configuration files. Often a programming language makes a straightforward and powerful configuration mechanism. Modern languages can easily compile small assemblers that can be used to assemble plugins for larger systems. If compilation is a pain, then there are scripting languages that can work well also.
It's often said that configuration files shouldn't use a programing language because they need to be edited by non-programmers. But how often is this the case? Do people really expect non-programmers to alter the transaction isolation levels of a complex server-side application? Non-language configuration files work well only to the extent they are simple. If they become complex then it's time to think about using a proper programming language.
One thing we're seeing in the Java world at the moment is a cacophony of configuration files, where every component has its own configuration files which are different to everyone else's. If you use a dozen of these components, you can easily end up with a dozen configuration files to keep in sync.
My advice here is to always provide a way to do all configuration easily with a programmatic interface, and then treat a separate configuration file as an optional feature. You can easily build configuration file handling to use the programmatic interface. If you are writing a component you then leave it up to your user whether to use the programmatic interface, your configuration file format, or to write their own custom configuration file format and tie it into the programmatic interface.
Separating Configuration from Use.
The important issue in all of this is to ensure that the configuration of services is separated from their use. Indeed this is a fundamental design principle that sits with the separation of interfaces from implementation. It's something we see within an object-oriented program when conditional logic decides which class to instantiate, and then future evaluations of that conditional are done through polymorphism rather than through duplicated conditional code.
If this separation is useful within a single code base, it's especially vital when you're using foreign elements such as components and services. The first question is whether you wish to defer the choice of implementation class to particular deployments. If so you need to use some implementation of plugin. Once you are using plugins then it's essential that the assembly of the plugins is done separately from the rest of the application so that you can substitute different configurations easily for different deployments. How you achieve this is secondary. This configuration mechanism can either configure a service locator, or use injection to configure objects directly.
Some further issues.
In this article, I've concentrated on the basic issues of service configuration using Dependency Injection and Service Locator. There are some more topics that play into this which also deserve attention, but I haven't had time yet to dig into. In particular there is the issue of life-cycle behavior. Some components have distinct life-cycle events: stop and starts for instance. Another issue is the growing interest in using aspect oriented ideas with these containers. Although I haven't considered this material in the article at the moment, I do hope to write more about this either by extending this article or by writing another.
You can find out a lot more about these ideas by looking at the web sites devoted to the lightweight containers. Surfing from the picocontainer and spring web sites will lead to you into much more discussion of these issues and a start on some of the further issues.
Concluding Thoughts.
The current rush of lightweight containers all have a common underlying pattern to how they do service assembly - the dependency injector pattern. Dependency Injection is a useful alternative to Service Locator. When building application classes the two are roughly equivalent, but I think Service Locator has a slight edge due to its more straightforward behavior. However if you are building classes to be used in multiple applications then Dependency Injection is a better choice.
If you use Dependency Injection there are a number of styles to choose between. I would suggest you follow constructor injection unless you run into one of the specific problems with that approach, in which case switch to setter injection. If you are choosing to build or obtain a container, look for one that supports both constructor and setter injection.
The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.

Inversion of Control.
Este conteúdo está desatualizado e não está mais sendo mantido. It is provided as a courtesy for individuals who are still using these technologies. Esta página pode conter URLs que eram válidos quando publicados originalmente, mas agora vinculam a sites ou páginas que não existem mais.
You have classes that have dependencies on services or components whose concrete type is specified at design time. In this example, ClassA has dependencies on ServiceA and ServiceB. Figure 1 illustrates this.
ClassA has dependencies on ServiceA and ServiceB.
This situation has the following problems:
To replace or update the dependencies, you need to change your classes' source code. The concrete implementations of the dependencies have to be available at compile time. Your classes are difficult to test in isolation because they have direct references to dependencies. This means that these dependencies cannot be replaced with stubs or mocks. Your classes contain repetitive code for creating, locating, and managing their dependencies.
Any of the following conditions justifies using the solution described in this pattern:
You want to decouple your classes from their dependencies so that the dependencies can be replaced or updated with minimal or no changes to your classes' source code. You want to write classes that depend on classes whose concrete implementations are not known at compile time. You want to test your classes in isolation, without using the dependencies. You want to decouple your classes from being responsible for locating and managing the lifetime of dependencies.
Delegate the function of selecting a concrete implementation type for the classes' dependencies to an external component or source.
Implementation Details.
The Inversion of Control pattern can be implemented in several ways. The Dependency Injection pattern and the Service Locator pattern are specialized versions of this pattern that delineate different implementations. Figure 2 illustrates the conceptual view of both patterns.
Conceptual view of the Service Locator and Dependency Injection patterns.
For more information about these patterns, see Dependency Injection and Service Locator.
The following are example implementations of the Inversion of Control pattern:
In the Configuration Modularity QuickStarts, the class ModuleA defined in the ModuleA project uses dependency injection to obtain a reference to the region manager service, as shown in the following code.
Because the ModuleA class is instantiated by a container and an instance of the region manager service is registered with the container, the ModuleA class receives a valid instance of the region manager service when it is constructed. Note that a mock instance of the region manager service can be supplied when testing the ModuleA class by passing the mock instance in the constructor's parameter.
Note that for testing purposes, you could configure the container to return a mock instance that implements the INewsController interface instead of the real implementation. This enables you to test the NewsModule class in isolation. The following code, extracted from the NewsModuleFixture test class (located in StockTraderRI. Modules. News. Tests\NewsModuleFixture. cs), shows how the NewsModule class can be tested in isolation using a mock instance for the INewsController interface.
Passivos
The Inversion of Control pattern has the following liabilities:
You need to implement a mechanism that provides the dependencies that are required by the object that is being initialized. There is added complexity to the source code, which makes it harder to understand.
Related Patterns.
The following patterns are related to the Inversion of Control pattern:
Dependency Injection. The Dependency Injection pattern is a specialization of the Inversion of Control pattern. The Dependency Injection pattern uses a builder object to initialize objects and provide the required dependencies to the object. Service Locator. The Service Locator pattern is a specialization of the Inversion of Control pattern. The Service Locator pattern introduces a locator object that objects use to resolve dependencies.
Mais Informações.
For more information on Inversion of Control patterns, see the following:
Este conteúdo está desatualizado e não está mais sendo mantido. It is provided as a courtesy for individuals who are still using these technologies. Esta página pode conter URLs que eram válidos quando publicados originalmente, mas agora vinculam a sites ou páginas que não existem mais.

Inversion of Control.
In this chapter, we will learn about IoC and how to implement it. This would be the first step towards achieving loose coupled design as illustrated by the following figure.
Inversion of Control (IoC) is a design principle (although, some people refer to it as a pattern). As the name suggests, it is used to invert different kinds of controls in object oriented design to achieve loose coupling. Here, the control means any additional responsibilities a class has other than its main responsibility, such as control over the flow of an application, control over the flow of an object creation or dependent object creation and binding.
IoC is all about inverting the control. To explain in layman's term, suppose you drive a car to your work place, it means you control the car. IoC principle suggests to invert the control, meaning instead of driving the car yourself, you hire a cab where another person will drive the car. Thus it is called inversion of the control from you to the cab driver. You don't have to drive a car yourself and let the driver do the driving so that you can focus on your main work.
IoC principle helps in designing loosely coupled classes which make them testable, maintainable and extensible.
Let's understand how IoC inverts the different kinds of control.
Control Over the Flow of a Program:
In a typical console application in C#, execution starts from the Main() function. The Main() function controls the flow of a program or in other words sequence of user interaction. Consider the following simple console program.
In the above example, the Main() function of the program class controls the flow of a program. It takes user's input for the first Name and last name. It saves the data, continues or exits the console depending upon the user's input. So here, flow of the control through the Main() function.
IoC can be applied to the above program by creating a GUI based application such as the following windows based application wherein the framework will handle the flow of a program using events.
This is a simple example of implementing IoC on the flow of a program.
Control Over the Dependent Object Creation:
IoC can also be applied in the way we create objects of dependent class. First of all, let's understand what we mean by dependency here.
Considere o seguinte exemplo.
In the above example, class A calls b. SomeMethod() to complete its task1. Class A cannot complete its task without class B and so you can say "Class A is dependent on class B" or "class B is a dependency of class A".
In object oriented design approach, classes need to interact with each other in order to complete one or more functionalities of an application such as in the above classes A and B. Class A creates and manages the life time of an object of class B. Essentially it controls the creation and life time of objects of dependency class.
IoC principle suggests to invert the control, means separate the controlling stuff to another class. In other words, invert the dependency creation control from the class A to another class as shown below.
As you can see above, class A uses Factory class to get an object of class B. Thus, we have inverted the dependent object creation from class A to Factory. The class A no longer creates an object of class B instead it uses Factory class to get the object of class B.
Let's understand this using a more practical example.
In an object oriented design, classes should be designed in loosely coupled way. Loosely coupled means changes in one class should not force other classes to change, so the whole application can become maintainable and extensible. Let's understand this by using typical n-tier architecture as depicted by the following figure.
In the typical n-tier architecture, the User Interface (UI) uses Service layer to retrieve or save the data. The service layer uses the BusinessLogic class to apply business rules on the data. The BusinessLogic class depends on the DataAccess class which retrieves or saves the data to the underlying database. This is simple n-tier architecture design. Let's focus on the BusinessLogic and DataAccess class to understand IoC.
The following is an example of BusinessLogic and DataAccess classes for customer.
As you can see in the above example, the CustomerBusinessLogic class depends on DataAccess class. It creates an object of the DataAccess class to get customer data.
Now, let's understand what's wrong with the above classes.
In the above example, CustomerBusinessLogic and DataAccess are tightly coupled classes because CustomerBusinessLogic class includes the reference of concrete DataAccess class. It also creates an object of DataAccess class and manages the lifetime of an object.
Problems in the above example classes:
CustomerBusinessLogic and DataAccess classes are tightly coupled classes. So, changes in the DataAccess class will lead to changes in the CustomerBusinessLogic class. For example, if we add, remove or rename any method in DataAccess class then we need to change CustomerBusinessLogic class accordingly. Suppose, customer data comes from different databases or web service in future we may need to create different classes for so it leads to changes in CustomerBusinessLogic class. CustomerBusinessLogic class creates an object of DataAccess class using new keyword. There may be multiple classes which use DataAccess class and create its object. So if you change the name of the class, then you need to find all the places in your source code where you create objects of DataAccess and make the change throughout the code. This is repetitive code for creating an object of same class and maintaining its dependencies. Because CustomerBusinessLogic class creates an object of concrete DataAccess class, it cannot be tested independently (TDD). DataAccess class cannot be replaced with mock class.
So, to solve the above problems and get a loosely coupled design, we can use IoC and DIP principles together. Remember, IoC is a principle not a pattern. It just gives high level design guidelines but does not give implementation details. You are free to implement IoC principle the way you want.
The following pattern (but not limited) implements IoC principle.
Let's use Factory pattern to implement IoC in the above example as the first step towards attaining loosely coupled classes.
First, create a simple Factory class which returns an object of DataAccess class as shown below.
Now, use this DataAccessFactory class in CustomerBusinessLogic class to get an object of DataAccess class.
As you can see, CustomerBusinessLogic class uses DataAccessFactory. GetCustomerDataAccessObj() method to get an object of DataAccess class instead of creating it using new keyword. Thus, we have inverted the control of creating an object of dependent class from CustomerBusinessLogic class to DataAccessFactory class.
This is a simple implementation of IoC and the first step towards achieving fully loose coupled design. As mentioned in the previous chapter, we will not achieve complete loosely coupled classes by only using IoC. Along with IoC we also need to use DIP, Strategy pattern, and DI (Dependency Injection).
Let's move to the second step to understand DIP and how it helps in achieving loose coupled design in the next chapter.

Inversion of control strategy pattern


Here is a code suggestion showing how to call the three methods.
If anyone can improve this and repost then I will delete this Comment.
The Interface classes should be moved to their own namespace.
// Handle to EventLog writer to write to the logs.
INofificationAction action = null;
public INofificationAction Action.
// This function will be called when the app pool has problem.
public void Notify(string message)
AppPoolWatcher watcher = new AppPoolWatcher();
int stew = 2; // either passed in or derived!!
EventLogWriter logWriter = new EventLogWriter();
else if (stew == 2)
EmailSender emailWriter = new EmailSender();
else if (stew == 3)
SMSSender smsWriter = new SMSSender();
public ActionResult Index()
// Remember that EventLogWriter, Email Sender an SMS Sender have all inherited.
// from INofificationAction interface.
//AppPoolWatcher sets the concrete class for an instance of INofificationAction.
AppPoolWatcher watcher = new AppPoolWatcher();
Definer def = new Definer();
AppPoolWatcher watcher1 = def. injectMessageDependency();
EventLogWriter logWriter = new EventLogWriter();
else if (stew == 2)
EmailSender emailWriter = new EmailSender();
else if (stew == 3)
SMSSender smsWriter = new SMSSender();
// This can be done in some class.
// This can be done in some other class.
watcher. Notify("Sample message to log");
watcher1.Notify("Message to send");
A comment below correctly says that there is a typo. The penny dropped for me when I ran the code. This is a brilliant article that extracts the concepts before diving in to development. I will use it to refactor a shared method adding different types of attachment to an email.
// public void ActOnNotification(string message);
void ActOnNotification(string message);
class EventLogWriter : INofificationAction.
public void ActOnNotification(string message)
// Write to event log here.
class EmailSender : INofificationAction.
public void ActOnNotification(string message)
// Send email from here.
class SMSSender : INofificationAction.
public void ActOnNotification(string message)
// Send SMS from here.
// Handle to EventLog writer to write to the logs.
INofificationAction action = null;
// This function will be called when the app pool has problem.

No comments:

Post a Comment