Cooperchip - Medical Management / Sys


Implementação do Design Patterns Template Method

Chegou a hora de darmos um salto de qualidade sobre as features mais avançadas dessa jornada sob o fantástico mundo do Asp.Net Mvc. Daremos início a implementação do nosso primeiro Design Patterns do zero: O Template Method, utilizando EntityFramework e CSharp. Siga-me, please!


Estilo de Transição

Selecione a transição que você mais gostar:
Nenhuma - Fade - Slide - Convex - Concave - Zoom

Design Patterns - Template Method em nossa App.


Vamos implementar um padrão para usarmos a Interface Fluent do Entity Framework de uma forma genérica e organizada.

Implementaremos uma classe abstrata que controlará nossos processos de Configurações de Entidades para a camada de dados.

E faremos isso de forma imutável e sequencialemte controlada.

Introdução:


A ideia inicial de padrão de projeto surgiu em 1977 com Christopher Alexander na área de Arquitetura (prédios e cidades). Seus livros e suas ideias foram usados de inspiração para os desenvolvedores de software. Além da arquitetura e do desenvolvimento de software, outras áreas como a Química e as áreas da Engenharia também possuem catálogos de soluções para problemas recorrentes.

Na área do desenvolvimento de software existe um catálogo de soluções desde 1995 com o livro "Design Patterns - Elements of Reusable Object-Oriented Software". Seus idealizadores foram Gamma, Helm, Johnson e Vlissides. Nesse livro são descritos diversos Padrões de Projetos.

Com o catálogo de Padrões de Projetos passamos a ter um vocabulário em comum, soluções descritas e com nomes descritivos, entre diversas outras vantagens.

Padrões de Projetos normalmente possuem Nome, Problema, Solução e Consequências/Forças.

Funcionamento:


O Padrão de Projeto Template Method define os passos de um algoritmo e permite que a implementação de um ou mais desses passos seja fornecida por subclasses. Assim, o Template Method protege o algoritmo e fornece métodos abstratos para que as subclasses possam implementá-los.

A definição oficial do padrão Template Method é: “O Padrão Template Method define o esqueleto de um algoritmo dentro de um método, transferindo alguns de seus passos para as subclasses. O Template Method permite que as subclasses redefinam certos passos de um algoritmo sem alterar a estrutura do próprio algoritmo”.

Portanto, o padrão Template Method basicamente oferece um método que define um algoritmo (uma sequência de passos) que pode, por sua vez, ser definido como abstrato para posteriormente ser implementado por uma subclasse. Pode-se notar que a estrutura do algoritmo fica inalterada mesmo com as subclasses fazendo parte da implementação.

Padrão Template Method Diagrama de Classe - (UML):


Cooperchip - Medical Management

Resumindo o Padrão Template Method:


No diagrama de classe acima temos a classe AbstractClass contendo o método “templateMethod()” que possui o algoritmo e que define os métodos “primitiveOperation1()” e “primitiveOperation2()” que são abstratos.

As classes concretas Concrete1 e Concrete2, implementam os métodos abstratos que serão chamados quando “templateMethod()” precisar delas.

Vale salientar que o método “templateMethod()” é final, ou seja, ele não pode ser sobrescrito, portanto seu algoritmo não pode ser mexido.

Já os métodos “primitiveOperation1()” e “primitiveOperation2()” podem ser sobrescritos. Além disso, ainda poderíamos ter um método concreto ou ainda um método final, que não poderia ser sobrescrito, sendo utilizado no algoritmo do templateMethod().

Isso ficará mais claro no exemplo de implementação abaixo.

Show me Code...!!!

Exemplo de implementação em Java utilizando o Padrão Template Method.


			public abstract class Treinos {
				final void treinoDiario() {
					preparoFisico();
					jogoTreino();
					treinoTatico();
				}				
				abstract void preparoFisico();
				abstract void jogoTreino();					
				final void treinoTatico() {
					System.out.println("Treino Tatico");
			}}				
			class TreinoNoMeioDaTemporada extends Treinos {				
				void preparoFisico() {
					System.out.println("Preparo Fisico Intenso.");
				}				
				void jogoTreino() {
					System.out.println("Jogo Treino com Equipe Reserva.");
			}}				
			class TreinoNoInicioDaTemporada extends Treinos {				
				void preparoFisico() {
					System.out.println("Preparo Fisico Leve.");
				}				
				void jogoTreino() {
					System.out.println("Jogo Treino com Equipe Junior.");
			}} 				
			

Listagem 1: Exemplo de implementação do Padrão Template Method.

Analisando o exemplo acima:


No exemplo acima temos a classe principal “Treinos” que tem o método “treinoDiario()” que, que por sua vez, tem como principal finalidade ser um algoritmo a ser seguido por todas as outras classes que estenderem essa classe.

Este método é final e não pode ser alterado, todos os treinos devem seguir estas etapas, no entanto, as classes “TreinoNoMeioDaTemporada” e “TreinoNoInicioDaTemporada” implementam os métodos abstratos “preparoFisico()” e “jogotreino()”.

Ambos podem ser alterados dependendo se o treino está sendo feito no inicio de uma temporada ou no meio dela.

Sendo assim, cada método é implementado por sua classe especifica, mas sempre seguindo o algoritmo.

O método “treinoTatico()” é definido pelo algoritmo e pela classe base, este método é concreto e final, portanto não pode ser alterado e é seguido por todos os treinamentos.

Nada impede, também, que tenhamos métodos concretos que possam ser sobrescritos nas subclasses ou simplesmente usados da sua classe base.

Ufa...!!!


Cooperchip - Medical Management
Show me Code now, please!

Classe de Configuração Genérica:


Nós já criamos algumas Classes de Configurações para mapear as propriedades do nosso Banco de Dados. Fizemos isso com a implementação das nossas ClassMaps. Ex.: UfMap, CidadeMap e BairroMap.

Entretanto, queremos mais. Mais código limpo, mais organização e, sobretudo, boas práticas. E isso nós faremos a partir de agora, implementando o Design Patterns Template Method.

Esse padrão foi explicado anteriormente, na teoria. Agora vamos por as mãos na massa e mostrar, na prática, como se faz, pois somos os melhores!

Vem comigo, no caminho eu explico!

Roteiro Config Database/Tables:


É comum, ao configuramos um banco de dados, que sigamos um roteiro pré-definido de passos "lógicos" e o nosso Template Method seguirá esse padrão, que lhe srpreenderá!

Cooperchip - Medical Management

(...) Config Table, Config Fields, Config PrimaryKey, Config ForeignKey.

Um Padrão com liberdade na implementação:


Nossa Classe de Configurações deverá atender a qualquer projeto na Solution, inclusive podendo ser exposta a outras Solutions através do Nuget Package Manager. Todas as tabelas seguem o mesmo roteiro, mas a maneira que cada uma implementa seus métodos concretos é de sua própria responsabilidade!

Cooperchip - Medical Management

Criaremos uma Class Library numa Camada Comum, reaproveitável em qualquer projeto, e esse será nosso primeiro passo para a implemantação, de fato, do nosso Design Patterns Template Method..

Criando a Classe CooperchipEntityAbstractConfig:


Esta é a classe responsável por criar nosso Template Method em seu Construtor e que Implementará a Classe do EF EntityTypeConfiguration, do pacote System.Data.Entity.ModelConfiguration.

Cooperchip - Medical Management

Instalando o EntityFramework:


Cooperchip - Medical Management

(...) O EF se faz necessário para usarmos a model "EntityTypeConfiguration", que trata das configurações da Interface Fluent.

EntityTypeConfiguration typeOf TEntity => Genérico:


Como estamos criando uma implementação genérica, passaremos o tipo TEntity, que pode representar qualquer tipo.

Cooperchip - Medical Management

(...) Da nossa classe CooperchipEntityAbstractConfig herdaremos a EntityTypeConfiguration com um tipo genérico.

Repassando nosso Tipo Genérico:


A classe do EF, EntityTypeConfiguration, não reconhece um tipo genérico, portanto precisamos repassá-lo da nossa classe CooperchipEntityAbstractConfig.

Cooperchip - Medical Management

A classe EntityTypeConfiguration está servindo de base para a nossa Classe Template.

Ainda apontando erro?


Sim! Esse erro é do EntityFramework, pois do jeito que declaramos os parâmetros/tipos pode parecer que teríamos condições de criar uma CooperchipEntityAbstractConfig de qualquer tipo. Isso implicaria em aceitarmos tipos Primitivos/Structs, como Int ou String. Faz sentido termos uma tabela desses tipos? Óbvio que não, certo?!

Cooperchip - Medical Management

Usaremos, pois, um limitador para especificarmos o que esperamos como Parâmetro/Tipo.

Resolvendo o problema da Tipagem Genérica!


Para resolvermos o problema da Tipagem Genérica para o EntityTypeConfiguration limitaremos, através da cláusula where, o tipo que passaremos!

Cooperchip - Medical Management

Nosso Template Method, finalmente, criado!


Neste ponto sobrescrevemos o contrutor da classe de template, criando, por fim, nosso Template Method. Ele é quem vai definir a sequência, passo a passo, em que nosso modelo será configurado!

Cooperchip - Medical Management

A partir desse Construtor chamaremos, na ordem predefinida, os métodos a serem implementados nas sub-classes.

Definindo a Sequência de Chamada dos Métodos


  • 1.Configurar Tabela
  • 2.Configurar Campos
  • 3.Configurar Chave Primária
  • 4.Configurar Chaves Estrangeiras / Relacionamentos
Cooperchip - Medical Management

Tornando minha Classe Template em AbstractClass.


  • 1.Preciso implementar os métodos de configurações da Interface Fluent;
  • 2.Criaremos Classes de Configurações que Herdarão de CooperchipEntityAbstractConfig de TEntity;
  • 3.Que por sua vez, herdará de EntityTypeConfiguration;
  • 4.Essas classes são como nossas UfMap, CidadeMap e BairroMap;
  • 5.No entanto as classes filhas é quem têm de implementar os métodos do nosso Template Method;
  • 6.Porém não é possível tornar nossa Classe Template em Interface, pois temos implementação no Construtor - nosso Template Method;
  • 7.A solução é tornar nossa classe template em uma AbstractClass;
Cooperchip - Medical Management

As classes filhas é que têm de implementar os métodos.


  • 1.Preciso implementar os métodos do meu construtor (Template Method);
  • 2.Mas essa tarefa é genérica, portanto não posso ter implementação na AbstractClass;
  • 3.Solução: Tornar os métodos Abstratos e sem implemantação, apenas as Assinaturas dos mesmos.
Cooperchip - Medical Management
(...) Quase lá. Aff. Rsrs.

Tornando as assinaturas dos métodos da classe template Abstratos e protegidos!


Cooperchip - Medical Management

Adicionando Referência para nossa Camada Comum / Genérica.


Com nossa Classe Template completa, chegou a hora de referenciá-la para fazermos uso do nosso Template Method, que é o Construtor da nossa Classe Template e, com isso, fazermos a Implementação Concreta dos Métodos de Configurações Genéricas para cada Entidade (TEntity), tipadas em sub-classes que farão uso da nossa template.

Cooperchip - Medical Management

Criando a Classe UfTypeConfiguration.


- Faremos o mesmo para CidadeTypeConfiguration e BairroTypeConfiguration. As três classes herdarão de CooperchipEntityAbstractConfig para o tipo TEntity, que nestes casos será, respectivamente, Uf, Cidade e Bairro.

Cooperchip - Medical Management

Antes disso criamos uma Solution Folder no nosso Projeto de Acesso a Dados.

Imprementações Concretas com Classes Internas.


Para cada implementação das classes concretas (Uf, Cidade e Bairro), herdaremos de CooperchipEntityAbstractConfig passando seus respectivos tipos (TEntity). Essas classes devem ser Internas mesmo, pois sua acessibilidade e visibilidade se restringe ao próprio projeto que as implementam.

Cooperchip - Medical Management

- Observe que a classe não tem um Modificador de Acesso, como Public, Private, Protect, Sealed, etc., o que a mantem interna.

ToTable vs DbSet + HasDatabaseGeneratedOptions.


As principais configurações são as citadas no título. Todas as outras já vimos quando implementamod as ClassMap.

Cooperchip - Medical Management

- Quanto aos nomes das tabelas algumas empresas, e/ou, DBAs insistem em usar seus Padrões - como Trigramação (¹), mas o EF nos permite usar nossas Model como setarmos em nossa classe de Contexto, com DbSet.


(¹) Trigramação é uma técnica de banco de dados que se utiliza de prefixos para a identificação de campos conforme suas tabelas, ou seja, quando ele for utilizado em outra tabela na forma de chave estrangeira (FK), tornar-se-á mais fácil a interpretação do relacionamento, pois será possível identificar pelo prefixo a tabela a que esse campo pertence. A trigramação é utilizada para facilitar a identificação da origem de cada atributo, utilizando as iniciais mais significativas da entidade para compor o nome do atributo. Ex: "TBL_Paciente". Usa-se "TBL" como prefixo de Tabela.

Interface Fluent => FluentApi (²).


Cooperchip - Medical Management

(²) Quando estamos configurando um Modelo de Dados atarvés do EntityTypeConfiguration ou mesmo no OnModelCreating da nossa Classe de Contexto, podemos usar métodos encadeados com a notação "Dot". Esta técnica é conhecida como Interface Fluent, por isso o EntityFramework a batizou de API Fluent ou FluentApi, como é mais conhecida!

Registrando nossas Classes Concretas de Configurações no OnModelCreating.


O método OnModelCreating recebe uma instância de DbModelBuilder, que é o responsável por fazer a correlação entre o modelo orientado a objeto - Nosso Domínio - e o modelo relacioanal - Nossas Tabelas. Ele é quem faz o match, por exemplo, entre a nossa propriedade Id e a coluna "PCT_ID" da nossa tabela de banco de dados Paciente.

Portanto precisamos avisar ao nosso ModelBuilder que temos uma classe personalizada de configuração, que no nosso caso, herda de CooperchipEntityAbstractConfig passando seu Model Type. Se não fizermos esse aviso nossas configurações serão simplesmente ignoradas e o (³) Padrão do EntityFramework será implementado.

Cooperchip - Medical Management

(³) Algumas das configurações padrão do EntityFramework é criar todos as propriedades do tipo String para nvarchar, com tamanho máximo!

Fim da Apresentação

Voltar para a Home