• Nenhum resultado encontrado

Figura 16: Arquitetura MVC - Struts2

Fluxo de processamento do pedido [20]:

1. O Cliente (Browser) envia uma mensagem ao servidor a pedir um determinado re- curso (e.g uma página).

2. O filtro StrutsPrepareAndExecuteFilter verifica o pedido, e caso alguma Action deva ser invocada, delega o controlo num sub-componente chamado ActionProxy que por sua vez consulta os ficheiros de configuração (i.e struts.xml), iniciando o processo de ActionInvocation.

3. Durante o processo de ActionInvocation são invocados os Interceptors e de seguida a Action. Na Action são efetuadas as operações pretendidas que podem ou não envolver ligações à base de dados. Após concluídas as operações necessárias os dados resul- tantes (scope variables data) são guardados na ValueStack do Action Context. Após o processamento da Action são novamente invocados os Interceptors.

4. StrutsPrepareAndExecuteFilter verifica o código de resultado definido na Action e pro- cura uma correspondência em struts.xml, invocando o Result definido.

5. No Result é feita a construção da página. A página (i.e JSP) acede ao ActionContext, obtendo assim todos os dados das variáveis definidas na Action anteriormente. Após

56 Capítulo 7. resultados Rails

Rails é um Framework push-MVC (também conhecido como action-based). O design pattern MVC em Rails é concebido através de 4 componentes principais (descritos no subcapítulo

3.4.3):

• ActionDispatch • ActionController • ActionView • ActiveRecord

Figura 17: Arquitetura MVC - Rails

O Controller é implementado através dos componentes ActionDispatch e ActionController, o Model através de ActiveRecord, e a View pelo ActionView. O diagrama apresentado na figura17descreve o fluxo de um pedido desde que chega ao servidor até que seja gerada a

respetiva resposta.

Fluxo de processamento do pedido:

1. O Cliente (Browser) envia uma mensagem ao servidor a pedir um determinado re- curso (e.g uma página).

2. O Rails Router verifica o recurso pedido e encaminha-o para o Controller específico.

7.4. Design Patterns 57

4. O Controller envia os resultados sob forma de variáveis de instância para a View (tem- plate ERB.HTML).

5. A View gera a página e envia a resposta de volta ao Controller.

6. O Controller envia a resposta ao Cliente.

7.4.2 Convention over Configuration - CoC

CoC é um paradigma de software que procura diminuir a número de configurações que são necessárias efetuar para interligar os diferentes componentes das aplicações. Desta forma o programador ganha simplicidade na construção de código e pode focar-se unicamente nas funcionalidades a desenvolver. Este paradigma é alcançado através da definição de um conjunto de convenções de nomes no ato de criação dos diversos componentes (Classes, Páginas Web, etc.).

Struts2

Por definição Struts2 não incorpora o Design Pattern CoC, sendo necessário que sejam de- finidas as configurações manualmente em struts.xml de cada componente. Apesar não ser uma funcionalidade embutida por defeito, esta é disponibilizada sob forma de um plugin oficial chamado Convention-Plugin que permite evitar quase por completo o uso de código de configuração. Utilizando este plugin é possível definir através de uma nomenclatura de nomes a localização de Actions, Results, Interceptors, etc.

A utilização deste plugin é automática desde que os seguintes requisitos sejam cumpridos: • As Action Classes tem de ficar armazenadas em packages e ou sub-packages que conte-

nham os termos struts2, action, actions;

• O nome das Action Classes deve terminar em "Action";

• As Actions Classes tem de implementar o o Interface Action ou herdar a classe Action- Support.

Na seguinte tabela3 abaixo pode ser compreendido com maior detalhe a lógica de ma-

peamento entre o URL e a Action Class.

URL Action Class

58 Capítulo 7. resultados

Na Action Class tal como referido anteriormente na descrição do fluxo de pedido em Struts2, na Action Class é definido um código de resultado (Result Code). Quando se uti- lizam os códigos de resultados definidos por convenção não é necessário definir a corres- pondência (JSP Template). Para que a convenção seja respeita é também necessário que os templates JSP estejam dentro do diretório "WEB-INF/content/template-name.jsp". Na tabela4

abaixo apresentada o exemplo em seguimento do anterior exemplo da tabela3.

Action Result Code View Template (JSP)

SUCCESS WEB-INF/content/cars.jsp

INPUT WEB-INF/content/cars-input.jsp

ERROR WEB-INF/content/cars-error.jsp

Tabela 4: Mapeamento do Action Result Code numa View Template (JSP)

Rails

Ao contrário do que acontece com Struts2, Rails não necessita de nenhum plugin extra à sua distribuição standard para que implemente configurações através de convenções. Con- tudo tal como em Struts2, é também possível definir manualmente as interligações entre componentes sempre que seja necessário efetuar um desvio da convenção de nomes.

No ficheiro de configuração routes.rb, que surge como primeiro filtro sempre que algum pedido é efetuado, define-se os recursos de um determinado URL. No exemplo abaixo pode ser visto um exemplo para a definição das rotas para o recurso cars.

1 resource : cars

Código 7.5: Definição de rotas http em Rails

Rails é um Framework que incentiva por definição o uso do design pattern REST, fazendo com que a definição efetuada na listagem de código7.5gere automaticamente as rotas que

se podem observar na tabela5.

Método HTTP URL GET /cars GET /cars/new POST /cars GET /cars/:id GET /cars/:id/edit PATCH/PUT /cars/:id DELETE /cars/:id

7.4. Design Patterns 59

À semelhança do que acontece em Struts2, os templates de resultados têm de estar num diretório de ficheiros específico, no caso de Rails é em: "app/views/cars/index.html.erb", onde "cars" é a pasta que contém todos os resultados para esse recurso. Sempre algum dos URLs da tabela 6 seja pedido e os respetivos componentes respeitem as regras anteriormente

definidas, as convenções assumem as configurações de interligação.

URL Controller Name Action Method Template Result

/cars CarsController index app/views/cars/index.html.erb

/cars/new CarsController new app/views/cars/new.html.erb

/cars/:id CarsController show app/views/cars/show.html.erb

/cars/:id/edit CarsController edit app/views/cars/edit.html.erb

/cars CarsController create N/A

/cars/:id CarsController update N/A

/cars/:id CarsController destroy N/A

Tabela 6: Mapeamento de Rotas REST em Rails

7.4.3 Inversion of Control - IoC

O desenvolvimento de aplicações web não se baseia apenas na etapa de desenvolvimento. Durante anos, a etapa de conceção foi muitas vezes negligenciada, mas nos dias que correm é uma fase fundamental para o sucesso na conceção de software. Para tal, é necessário que existam preocupações sobre vários atributos do software, como por exemplo, a sua testabilidade e extensibilidade. São estes aspetos que influenciam a arquitetura do mesmo. Para que se verifiquem os atributos de qualidade mencionados, é necessário que exista, entre outros, um baixo nível de acoplamento entre as classes. Neste subcapítulo serão abordadas algumas formas de implementar IoC com o objetivo de alcançar uma arquitetura de software de baixo acoplamento.

Inversão de Controlo como padrão arquitetural permite:

• Existir um fraco acoplamento da execução de determinadas tarefas da implementação; • Cada módulo foca-se apenas no propósito para o qual foi desenhado;

• Os módulos mantêm-se apenas fiéis aos seus contratos (interfaces), não fazendo pre- sunções acerca de outros;

• Alterações efetuadas em módulos, não deverão afetar outros módulos ou afetar o menos possível.

O IoC é, portanto, um paradigma arquitetural, que tem como objetivo, dar um maior controlo aos componentes principais da aplicação, que são os que fazem com que as tarefas

60 Capítulo 7. resultados Struts2

Struts2 não dispõe de mecanismos integrados por defeito para a implementação de IoC, contudo existem um conjunto de opções conhecidas para a implementação deste design pat- tern. Por esta razão a implementação de software efetuada não contemplou IoC por não ser um padrão standard por defeito. Apesar de tudo foi feito um trabalho extra com o intuito de entender qual a relação entre custo/beneficio na implementação de IoC. Após algum estudo verificou-se que uma das soluções conhecidas, e talvez a melhor aceite na implementação IoC no âmbito do desenvolvimento empresarial é a integração do Spring Framework. Spring Framework é composto por um container que tem como função a cria- ção (instanciação) de classes aplicacionais, e define as dependências entre elas através de um arquivo de configuração. Desta forma o Spring Framework permite atingir o objetivo inicialmente abordado do baixo acoplamento entre classes [21].

Nas tecnologias JEE existem várias formas de implementar IoC. Na figura18são apresen-

tadas algumas formas de implementação de IoC, entre as quais se encontra a ser utilizada por Spring Framework conhecida como Dependency Injection - DI através de Setter Injection.

Figura 18: Formas de implementação de IoC em JEE

Tal como referido, a implementação de SeTaRe efetuada em Struts2 não contempla IoC, dado que o objetivo desta dissertação prende-se ao estudo das tecnologias no seu estado mais standard. Contudo será demonstrado quais as mudanças a serem feitas com o objetivo de tornar a aplicação mais independente entre si.

Implementação IoC

A implementação é possível através da utilização e rápida configuração do plugin struts2- spring-plugin.

Através deste plugin, podem ser definidas todas as dependências entre os diferentes Beans, através do ficheiro de configuração applicationContext que funciona como Container. No

7.4. Design Patterns 61

exemplo 7.6 é apresentada da dependência do LoginAction que tem como propriedade o

user DAO.

...

<bean id=" beanUserDAO " class =" dao . impl . UserDAO ">

<property name =" sessionFactory " ref =" sessionFactory " /> </bean >

<bean id=" beanLogin " class =" actions . LoginAction " scope =" prototype "> <property name =" userDAO " ref =" beanUserDAO " />

</bean > ...

Código 7.6: Definição dos Beans com Spring

Para que seja respeitado o IoC é também efetuar alterações ao nível dos DAOs (Model). Os DAOs passam agora a implementar Interfaces. Desta forma através de Setter Injection é possível que as dependências sejam injetadas nas Actions sem que sejam criadas novas instâncias através de código, como é apresentado no exemplo7.7.

public class LoginAction extends ActionSupport { ...

private IUserDAO userDAO ;

public void setUserDAO ( IUserDAO userDAO ) { this . userDAO = userDAO ;

} ...

public String execute () throws Exception { userDAO . findByEmail (" email@gmail . com "); ...

} }

Código 7.7: Struts2 Action com IoC

Assim, o Spring gere as dependências automaticamente, injetando-as em tempo de exe- cução quando são necessárias.

Rails

Rails por definição não apresenta ou sugere qualquer tipo de mecanismo para implementa- ção IoC como acontece com Struts2. Como já foi referido no início do subcapítulo 8.4.3 , o IoC é um design pattern, que tem como objetivo quebrar o forte acoplamento entre classes, nomeadamente no que diz respeito à criação de novas instâncias de uma classe dentro de

62 Capítulo 7. resultados

estáticas quando referenciamos uma classe pelo nome (ato de criação “new”) não existe am- biguidade, o que significa que estamos perante um caso de acoplamento apertado da classe. Em linguagens dinâmicas “new X” serve apenas como um espaço reservado para instanciar qualquer classe definida como “X” num determinado ponto de execução, o que significa que estamos perante um caso de fraco acoplamento, pois a única ligação é o nome “X”. No seguinte exemplo de código7.8 poderá ser compreendida a dinâmica da linguagem Ruby

na injeção da dependência Agency [22].

class Car

attr_reader :brand , : day_price , : agency def initialize (brand , day_price , year , agency )

@brand = brand

@day_price = day_price @agency = agency

end

def final_cost ( total_days = 1)

( day_price * total_days ) * agency . tax end

end

Car expects a 'Duck ' that knows 'tax '

Car . new (" Ferrari ", " 300 ", Agency . new (1, " Europcar ", 1.23) ). final_cost (3)

Código 7.8: Injeção de Dependências em Ruby

A Classe Car utiliza a variável @agency para receber a dependência e o método agency para aceder a propriedades do objeto. Desta forma Car não sabe nem se interessa se o objeto é uma instância da Classe Agency. A Classe Car apenas sabe que detém um objeto que responde a tax.

De uma maneira geral IoC permite que sejam feitas ligações dinâmicas (Dinamic Binding) e que a linguagem se torne dinâmica (em Java, é possível alcançar através de configurações XML ou annotations). Desta forma pode afirmar-se que os Containers IoC são de alguma forma desnecessários quando se trata de linguagens dinâmicas, como é o caso de Ruby, pois tratam-se de funcionalidades já de alguma forma consideradas nativas. No entanto IoC e DI são conceitos igualmente importantes tanto em linguagens dinâmicas ou estáticas, pelas mesmas razões [23]. Ao contrário do que acontece em Java, Ruby não necessita de IoC containers nem de DI Frameworks adicionais, pelo que os princípios são igualmente úteis.

“Frameworks de DI são desnecessários. Em ambientes mais rígidos, têm o seu valor. Em ambientes ágeis como Ruby, não muito. Os padrões em si podem ser

Documentos relacionados