Recentemente, sempre fui exposto a princípios ou padrões de programação, como o COI (inversão de controle), DI (injeção de dependência), e estes são o núcleo das famosas estruturas de Java Spring, Struts etc. Em resposta a isso, verifiquei vários itens na Wikipedia e emprestaram livros relevantes da biblioteca. Depois de lê -los, tenho algum entendimento. Agora vou combinar as explicações no livro e meu próprio processamento e resolvê -las da seguinte maneira:
EG1
Descrição do problema:
Desenvolva um sistema que possa gerar relatórios no formato Excel ou PDF de acordo com diferentes requisitos, como relatórios diários, relatórios mensais etc.
Solução:
De acordo com o princípio da "programação orientada para interface", a interface e a implementação devem ser separadas, ou seja, a função de gerar relatórios é extraída em um reportGenerator de interface geral e duas implementações que geram relatórios do Excel e PDF nos formatos Excel e PDF são fornecidos. O cliente obtém a função de impressão de relatório correspondente através do provedor de serviços Relatórios.
Método de implementação:
De acordo com o exposto, o diagrama de aula a seguir é obtido:
Implementação de código:
interface ReportGenerator {public void Generate (tabela de tabela); } classe ExcelGenerator implementa o relatório do reportGenerator {public void Generate (tabela Tabela) {System.out.println ("Gere um relatório do Excel ..."); }} classe PDFGenerator implementa o relatório do reportGenerator {public void Generate (tabela Tabela) {System.out.println ("Gere um relatório PDF ..."); }} classe relatórios Service {// Responsável pela criação do gerador de relatórios para necessidades específicas Relatórios privados gerador = new PDFGenerator (); // gerador de relatório estático privado = new ExcelGenerator (); public void getDailyReport (data) {tabela.setDate (data); // ... generator.gereate (tabela); } public void getMonthlyReport (mês) {table.setmonth (mês); // ... generator.gereate (tabela); }} classe pública client {public static void main (string [] args) {reportservice reportservice = new reportservice (); relatórios.getDailyReport (new Date ()); //reportService.getMonthlyReport(new date ()); }}
EG2
Descrição do problema:
Conforme mostrado nos comentários no código acima, o gerador de relatório específico é criado internamente na classe Relatórios, de modo que os relatórios de serviço se baseiam diretamente no PDFGenerator ou no ExcelGenerator, e esse óbvio acoplamento apertado deve ser eliminado.
Solução: Introduzir contêineres para introduzir um gerente intermediário, ou seja, o contêiner (contêiner), que gerencia uniformemente os objetos envolvidos no sistema de relatórios (aqui está um componente, chamamos de feijão), incluindo relatórios e vários xxgeneradores. Aqui você usa uma instância de hashmap na forma de um par de valores-chave para salvar esses feijões.
Método de implementação:
O diagrama de classe é obtido da seguinte maneira:
Implementação de código:
classe Container {// Salve vários componentes necessários em pares de valores-chave Mapa estático privado Bean <String, Object> Beans; public container () {Beans = new Hashmap <String, Object> (); // Crie e salve e salve o relatório de relatório Relatório Relatório ReportGenerator = new PDFGenerator (); beans.put ("RelatórioGenerator", RelatórioGenerator); // Obtenha e gerencie a referência do relatórios relatórios relatórios relatórios = new reportservice (); beans.put ("relatórios", relatórios); } public static objeto getBean (string id) {return beans.get (id); }} classe relatórios Service {// elimine o relacionamento de acoplamento apertado e substitua -o pelo contêiner // gerador de relatório estático privado = new PDFGenerator (); Gerador do gerador de relatórios privados Relatórios = (RelatórioGenerator) container.getBean ("RelatórioGenerator"); public void getDailyReport (data) {tabela.setDate (data); generator.Generate (tabela); } public void getMonthlyReport (mês) {table.setmonth (mês); generator.Generate (tabela); }} public class cliente {public static void main (string [] args) {contêiner contêiner = new container (); Relatórios relatórios relatórios = (relatórios) container.getBean ("relatórios"); relatórios.getDailyReport (new Date ()); //reportService.getMonthlyReport(new date ()); }}
O gráfico de tempo é aproximadamente o seguinte:
Efeito:
Como mostrado acima, o relatórios de serviço não está mais diretamente associado ao reportGenerator específico. Ele usou contêineres para isolar a interface e a implementação, melhorando a reutilização dos grãos componentes do sistema. No momento, você também pode usar arquivos de configuração para obter a definição de componentes específicos no contêiner em tempo real.
EG3
Descrição do problema:
No entanto, se você olhar para o diagrama de classe acima, é fácil descobrir que existe uma relação de mão dupla entre o Relatórios e o contêiner, e eles têm dependências mútuas. E, se você deseja reutilizar o Relatórios, também depende diretamente da lógica de pesquisa específica de um único contêiner. Se outros contêineres tiverem mecanismos de pesquisa de componentes diferentes (como o JNDI), reutilizar o Service Service no momento significa que a lógica de pesquisa interna do contêiner precisa ser modificada.
Solução: Introdução ao localizador de serviços
A reintrodução de um localizador de serviço de camada indireta é usada para fornecer uma interface para a lógica de pesquisa de componentes. Consulte a descrição na Wikipedia ou a descrição dela por Java EE 1 e 2. Isso permitirá o possível isolamento de possíveis mudanças.
Método de implementação:
O diagrama de classe é o seguinte:
Implementação de código:
// No aplicativo real, você pode usar a interface para fornecer uma classe de interface unificada ServiceLocator {contêiner estático privado = novo contêiner (); public static reportGenerator getReportGenerator () {return (relatgeGenerator) container.getBean ("reportgeGeReAator"); }} classe relatórios Service {private ReportGenerator ReportGenerator = serviceLocator.getReportGenerator (); // ...}EG4
Descrição do problema:
No entanto, se está introduzindo contêiner ou usando o localizador de serviços, o relatório é "ativo" na pesquisa e criação de componentes específicos, o que significa que, como cliente, o relatório deve ser claro sobre o que precisa, onde pode ser obtido e como pode ser obtido. De repente, detalhes lógicos específicos devem ser adicionados por causa do que, onde e como.
Por exemplo, no método de implementação anterior de 'Introdução ao contêiner', há o seguinte código:
classe relatórios Service {// elimine o relacionamento de acoplamento apertado e substitua -o pelo contêiner // private estático RelatórioGenerator Generator = new PDFGenerator (); // Encontre o gerador de relatórios privados = (RelatórioGenerator) contêiner .getBean ("RelatórioGenerator");
No método de implementação de 'Introdução ao Localizador de Serviços', há o seguinte código:
classe serviceLocator {contêiner privatestatic contêiner = new container (); publicstatic ReportGenerator getReportGenerator () {// ainda é container.getBean (), apenas um delegado é usado devolução (relatórios do reportgenerator) container.getBean ("reportGeNeAator"); }} classe relatórios Service {// ReportsVice No final, ele ainda 'ativa' pesquisa e delega para o ServiceLocator Private ReportGenerator ReportGenerator = serviceLocator.getReportGenerator (); }
Solução:
Nesse caso, a alteração 'ativa' para 'passiva', sem dúvida, reduzirá o conhecimento interno do relatório (ou seja, a lógica de encontrar componentes). De acordo com o princípio da inversão de controle (IOC), esse puxão (atração, ativo) é convertido em um modo push (push, passivo).
Por exemplo, a assinatura do RSS que geralmente usamos é um aplicativo push, que nos salva o aborrecimento de fazer login em nosso site favorito várias vezes ao dia para obter ativamente as atualizações do artigo.
A injeção de dependência (DI) alcança esse tipo de recepção passiva e reduz os problemas dos clientes (aqui, relatórios) contendo lógica complexa e conhecimento demais.
Método de implementação:
Como queremos ser uma recepção 'passiva', devemos voltar ao exemplo do contêiner sem usar o modo Localizador de Serviço. O diagrama de classes modificado é obtido a partir disso da seguinte forma:
O diagrama de classe original é o seguinte. Você pode conferir e prestar atenção aos avisos de comentários:
Implementação de código:
Para permitir que o exemplo seja compilado e executado, e usar os resultados em execução do código de rastreamento para instanciar explicitamente o diagrama inteiro de classe e cooperar entre si em sequência, muitas declarações de impressão numeradas e duas classes insignificantes foram adicionadas ao construtor de cada classe, que é um pouco insultuoso, como a seguir::
importar java.util.date; importar java.util.hashmap; importar java.util.map; // Para poder compilar e executar, existem mais duas classes insignificantes. Month da classe {} classe Tabela {publicVoid setDate (data) {} publicVoid Setmonth (mês mês) {}} // • de ExcelGenerator ... "); } publicVoid Generate (tabela Tabela) {System.out.println ("Gere um relatório do Excel ..."); }} classe PDFGenerator implementa o relatório do reportGenerator {public pdfgenerator () {System.out.println ("2 ... Inicie a inicialização do PDFGenerator ..."); } publicVoid Generate (tabela Tabela) {System.out.println ("Gere um relatório em PDF ..."); }} // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Obtenha e gerencie a referência do relatórios relatórios relatórios relatórios = new reportservice (); // injetar a instância do relatório específico criado acima relatórios.SetReportGenerator (relatário); beans.put ("relatórios", relatórios); System.out.println ("5 ... contêiner de inicialização final ..."); } objeto publicstatic getBean (string id) {System.out.println ("Last Get Component de Serviço ... getBean () ->" + id + "..."); returnbeanS.get (id); }} classe relatórios Service {// Generator de relatório estático privado = new PDFGenerator (); // elimine a relação de acoplamento apertada acima e substitua -o pelo contêiner // gerador de relatórios privados = (relatórios) contêiner // .getBean ("reportgenerator"); // Remova a pesquisa "ativa" acima e forneça campos privados para salvar o objeto injetado externamente o gerador de relatório privado; // injete o publicVoid de fora no formulário setter setReportGenerator (gerador de relatórios) {System.out.println ("4 ... inicie o injeção de reportgenerator ..."); this.Generator = gerador; } tabela privada tabela = new tabela (); public reportservice () {System.out.println ("3 ... Iniciar relatórios de inicialização ..."); } publicVoid getDailyReport (data) {tabela.setDate (data); generator.Generate (tabela); } publicVoid getMonthlyReport (mês) {tabela.setmonth (mês); generator.Generate (tabela); }} publicClass Client {publicstaticVoid Main (String [] args) {// Inicialize o contêiner new Container (); Relatórios relatórios relatórios = (relatórios) contêiner .getBean ("relatórios"); relatórios.getDailyReport (new Date ()); // reportservice.getMonthlyReport (new Date ()); }}
Resultados em execução:
1 ... Iniciar o recipiente de inicialização ... 2 ... Iniciar inicialização PDFGenerator ... 3 ... Iniciar Relatórios de inicialização Service ... 4 ... Iniciar o Injetar RelatórioGenerator ... 5 ... Contêiner de inicialização final ... finalmente obtenha o componente de serviço ... getBean () -> Relatórios
Perceber:
1. De acordo com a ordem de impressão dos resultados da execução acima, pode -se observar que os números específicos adicionados ao código são razoáveis, o que simula o processo de execução do programa, para que não desenhe mais diagramas de sequência.
2. Observe que o uso do COI e DI neste exemplo é baseado no relatórios como o cliente (ou seja, o componente Demander) e o código de teste na classe do cliente principal () no código é o usuário final do componente de serviço, mas o que ele precisa não é o componente, mas os serviços que o componente possui.
3. De fato, no clipe da caixa de primavera, a inicialização do contêiner obviamente não é o que o cliente do usuário final deve fazer, ele deve ser iniciado com antecedência pelo provedor de serviços.
4. No cliente final do usuário, ainda usamos o container.getBean ("relatórios") para obter componentes de serviço que foram instanciados no construtor de contêineres com antecedência. Em aplicativos específicos, os componentes de serviço disponíveis geralmente são implantados no servidor usando XML e outros arquivos de configuração e, em seguida, os arquivos de configuração são lidos pelo contêiner e combinados com a tecnologia de reflexão para criar e injetar componentes de serviço específicos.
analisar:
Anteriormente, o relatório solicitou ativamente o componente de serviço do contêiner, mas agora esperava passivamente a injeção de contêiner (injeção, ou seja, push). Obviamente, o controle é transferido do módulo subjacente (o relatório é o componente Demander) para o módulo de alto nível (o contêiner é o provedor do componente), ou seja, o controle é revertido.