orientação a objetos no delphi - por onde começar (i)

11

Click here to load reader

Upload: ryan-padilha

Post on 22-Jun-2015

4.229 views

Category:

Software


2 download

TRANSCRIPT

Page 1: Orientação a Objetos no Delphi - Por onde começar (I)

Orientação a Objetos no Delphi: Por onde começar? – Parte I

Ryan Bruno C Padilha

[email protected]

http://ryanpadilha.com.br

Objetivo deste artigo

Este artigo é o primeiro de uma série de três artigos onde iremos desenvolver uma aplicação

básica de controle de estoque. A primeira parte da série tem como objetivo fornecer uma

introdução ao paradigma orientado a objetos na linguagem Object Pascal, que é a linguagem

base do ambiente Delphi. A orientação a objetos, comumente chamada de OO é

fundamentada em trazer os objetos da vida real para representar uma entidade na aplicação

por meio de um tipo bem definido, ou seja, através de classes. Antes do surgimento da OO,

muitos desenvolvedores utilizavam ou ainda utilizam o paradigma estruturado, do qual com o

passar do tempo se mostrou pouco flexível, com baixa reutilização de código e inadequado a

projetos de software de grande complexidade.

1. Introdução ao Paradigma Orientado a Objeto

O Object Pascal é uma linguagem híbrida, pois além da orientação a objetos possui também

uma parte da antiga linguagem estruturada - Pascal. Por este motivo não somos forçados a

programar cem por cento orientado a objetos no Delphi, como ocorre em outras linguagens de

programação como Java e C# .NET – que oferecem suporte somente a este paradigma em

questão.

Muitas pessoas quando questionadas se programam utilizando o conceito de orientação a

objetos no Delphi, respondem afirmativamente, porém levando a conversa mais adiante fica

claro que a maioria delas programa no nível do designer, que não exige um conhecimento

profundo dos conceitos da OO. É chamado nível do designer a prática de programação que

utiliza os componentes visuais do Delphi (VCL – Visual Component Library), necessitando

apenas conhecer a sintaxe da linguagem. A diferença aqui é sutil, porém os paradigmas

abordados – orientado a objetos e estruturado – são na teoria e prática diferentes.

A orientação a objetos é amplamente utilizada na análise, projeto e implementação de

projetos de software baseado na composição e interação entre diversas unidades de software

conhecidas como objetos. Os objetos nada mais são do que instâncias de uma determinada

classe (modelo), podem se relacionar entre si através de associações (agregação /

composição); trocar mensagens através de chamadas de métodos (operações); ser objetos

especialistas ou mais genéricos através de herança. Resumidamente, as principais

características da OO são: as classes, a herança, o polimorfismo, seguidas por abstração e

encapsulamento.

Para quem está entrando em contato com os conceito da orientação a objetos neste

momento, pode achar tudo muito confuso e difícil, e isto é esperado, porém, na realidade é

bem mais fácil do que se imagina. Com a utilização constante e um maior entendimento do

paradigma OO, será notado que é mais fácil a implementação e principalmente a manutenção

Page 2: Orientação a Objetos no Delphi - Por onde começar (I)

nos projetos de software. Iremos elucidar os principais termos e definições gerais da

orientação a objetos.

1.1 Conceitos Essenciais

Classe

Tipo de dado bem definido através de atributos (variáveis) que armazenam estados (valores);

o comportamento das instâncias dessa classe (conjunto de objetos semelhantes) é definido

através dos métodos, na forma de procedimentos ou funções, que representam as operações

que os mesmos podem realizar. Há dois tipos de classes: 1) Concreta: definida como uma

classe que pode ser instanciada diretamente por um objeto; 2) Abstrata: declarada como uma

classe que pode apenas ser estendida, ou seja, servindo como modelo ou classe base

(superclasse) na hierarquia de classes que estiver inserida, não sendo possível a instanciação

direta por um objeto.

Uma classe é declarada através do uso da palavra reservada class, vejamos a estrutura básica

de uma classe:

Type

// classe definida como TMinhaClasse

// toda classe herda de TObject, sendo sua declaração facultativa

TMinhaClasse = class(TObject)

private

{ atributos / métodos privados }

protected

{ atributos / métodos protegidos }

public

{ atributos / métodos públicos }

end; // fim da declaração da classe TMinhaClasse

Para melhor entendimento segue o exemplo de uma classe TCliente que pode ser

implementada no Delphi.

Type

TCliente = class(TObject)

private

function Inserir(): Boolean;

function Update(): Boolean;

protected

_codigo: String;

_nome: String;

_telefone: String;

public

// propriedades – encapsulamento de atributos

property Codigo: String read getCodigo write setCodigo;

property Nome: String read getNome write setNome;

Page 3: Orientação a Objetos no Delphi - Por onde começar (I)

property Telefone: String read getNome write setNome;

// métodos – podem ser declarados como functions ou procedures

function Validar(): Boolean;

function Merge(): Boolean;

function Delete(): Boolean;

function getObject(Id: String): Boolean;

procedure getMaxId;

end;

implementation

// implementação dos métodos declarados acima

// código completo omitido para não estender demais o tópico

Objeto

É uma instância de uma classe, ou seja, é uma variável (dinâmica) do tipo definido pela classe.

Possuindo a capacidade de armazenar estados através de seus atributos e realizar operações

através de seus métodos, definindo seu comportamento. O estado de um objeto pode ser

persistido (armazenado) em um banco de dados objeto-relacional.

Os objetos quando instanciados através da invocação do método Create (método construtor),

são automaticamente alocados na memória Heap, local na memória principal que armazena

todos os objetos que serão utilizados na aplicação. Quando um método que utiliza o objeto é

finalizado, o objeto fica passível de ser coletado pelo Garbage Collector, através da chamada

do método Free (método destrutor).

Todos os objetos no Delphi herdam automaticamente da classe TObject, que possui alguns

métodos auxiliares tais como os métodos especiais Create e Free, porém podemos criar nossos

próprios métodos Create e Free, para inicializar e destruir, respectivamente, conforme

necessário. Agora que temos uma classe definida (TCliente), será demonstrado como

instanciar objetos. Uma variável do tipo da classe deve ser declarada, conforme abaixo:

var

Cliente: TCliente;

Begin

Cliente := TCliente.Create; // instancia o objeto cliente na memória

// setando valores aos atributos do objeto ‘Cliente’

Cliente.Codigo := ‘1’;

Cliente.Nome := ‘Revista Active Delphi’;

Cliente.Telefone := ‘(16) 3024-8713’;

// chamando o método Merge da classe TCliente, que irá persistir o estado do objeto

if Cliente.Merge() then

ShowMessage(‘Cliente Cadastrado com Sucesso!’)

Else

Page 4: Orientação a Objetos no Delphi - Por onde começar (I)

ShowMessage(‘Erro ao Gravar o Cliente!’);

Cliente.Free; // chamando o método destrutor, objeto ‘Cliente’ desalocado da memória

end;

Herança

É o mecanismo do qual uma subclasse pode estender outra classe (superclasse), herdando os

atributos e métodos desta, definindo um novo tipo de classe a partir de outra previamente

existente, reutilizando código. Define-se assim um relacionamento de pai/filho entre tipos, o

que origina a hierarquia de classes. Há dois tipos de herança: 1) herança de implementação: a

classe derivada (subclasse) somente poderá assumir uma classe base na herança; 2) herança

de interface: uma ou mais interfaces podem ser referenciadas na herança.

Encapsulamento

Consiste na separação de aspectos internos e externos de um objeto, escondendo os detalhes

de implementação de um objeto. Utilizado amplamente para impedir o acesso direto ao

estado de um objeto (seus atributos). Está ligado a implementação, é necessário expor uma

interface simples e funcional para um objeto, que são definidos como públicos. O programador

somente precisa conhecer a interface do objeto para utilizá-lo, podendo assim alterar a

implementação interna de uma classe sem causar problemas as unidades que as usem.

O recomendado é fornecer acesso aos atributos da classe sempre através de métodos

acessores, que podem operar corretamente com os mesmos, nunca permitir acesso direto aos

atributos, pois com isto perdemos o controle sobre o estado do objeto, tornando-o em alguns

casos inconsistente. O controle do que está visível ou não, a interface pública de uma classe é

definida através dos modificadores de visibilidade que veremos mais adiante.

Modificadores de Visibilidade

Definem a visibilidade de métodos e atributos dentro de uma classe. O Object Pascal possui

três especificadores de acesso básico:

Public (+): Métodos e atributos podem ser acessados de fora da classe, a partir de qualquer

outra unidade. Subclasses herdam todas as assinaturas.

Private (-): Métodos e atributos são somente acessados de dentro da classe, invisível para

outras unidades. Os membros de uma superclasse não são herdados pelas suas subclasses.

Protected (#): Oferece um nível intermediário de acesso entre o public e private. Os membros

de uma superclasse podem ser acessados por membros dessa superclasse, por membros de

suas subclasses e por membros de outras classes no mesmo pacote, ou seja, através da

hierarquia de classes.

O mecanismo em Object Pascal para encapsular os atributos em uma classe é definido como

Property (propriedade), sobrecarregando as operações de leitura (read) e escrita (write)

executadas quando a propriedade for acessada. Permite através de métodos acessores que se

trabalhe diretamente com os atributos, realizando chamadas a métodos. Ao se pensar em

Page 5: Orientação a Objetos no Delphi - Por onde começar (I)

encapsulamento de atributos, os quais devem sempre estar protegidos, a declaração Property

desempenha papel fundamental ao proteger o objeto, definindo uma forma padronizada de

acesso ao estado do objeto.

Para utilizar Property, os atributos devem ser declarados como private ou protected, os

métodos como private ou protected, e as propriedades como public.

Property NomePropriedade: TipoDado

read [MetodoDeLeitura ou campo] // método get

write [MetodoDeEscrita ou campo; // método set

Na classe TCliente, encapsulamos os atributos do objeto através de Properties, e definimos um

método para efetuar a leitura e escrita em cada propriedade, esses métodos são os famosos

getters e setters, que são métodos auxiliares que operam sobre os atributos.

Polimorfismo

É o meio pelo qual duas ou mais classes derivadas de uma mesma superclasse podem executar

métodos que contem a mesma assinatura (nomenclatura e lista de parâmetros), porém com

comportamento diferentes. Como exemplo temos a superclasse TVeiculo que possui o método

acelerar, uma subclasse TCarro que herda de TVeiculo o método acelerar, e outra subclasse

TAviao que herda também de TVeiculo o método acelerar; porém o método herdado nas duas

subclasses serão re-escritos pois o mecanismo de aceleração de um carro pode ser diferente

de um avião. Concluí-se que apesar das subclasses terem a mesma assinatura, o método

acelerar, possuem implementações diferentes em cada classe, daí o nome polimorfismo –

muitas formas. Encontramos duas formas de implementar o polimorfismo:

1) Sobrecarga: Métodos da mesma classe podem ter o mesmo nome, desde que possuam

quantidade ou tipo de parâmetros diferentes, declarados usando a palavra reservada

overload.

2) Sobrescrita: Métodos da classe derivada podem ter assinaturas idênticas ao da superclasse,

inclusive com parâmetros iguais, declarados usando a palavra reservada override;

Type

TVeiculo = class(TObject) // superclasse (classe base)

protected

procedure acelerar(Value: Integer); virtual;

end;

TCarro = class(TVeiculo) // classe TCarro herda de TVeiculo

protected

procedure acelerar(Value: Integer); override; // re-escrevendo o método acelerar

end;

TAviao = class(TVeiculo) // classe TAviao herda de TVeiculo

protected

Page 6: Orientação a Objetos no Delphi - Por onde começar (I)

procedure acelerar(Value: Integer); override; overload;

procedure acelerar(Value: Integer; Altura: Double); overload; // sobrecarga método

end;

Abstração

É definido características essenciais de um objeto que o distingue de outros objetos quaisquer.

Obtemos uma separação do que é essencial para o comportamento do objeto de sua

implementação. Na hierarquia de classes, partimos das classes básicas para as específicas.

Uma classe abstrata serve apenas como base para classes especializadas ou concretas, não

possui implementação e não pode ser instanciada diretamente.

Em Object Pascal pode-se definir um método abstrato em uma superclasse e só implementá-lo

em subclasses, reforçando o polimorfismo. A definição de métodos abstratos é realizado

utilizando a palavra reservada abstract, veja abaixo:

Type

TClasseAbstrata = class

public

function Merge(): Boolean; virtual; abstract;

end;

Associação

É o mecanismo pelo qual um objeto utiliza os recursos de outro. Uma das interações mais ricas

na orientação a objetos é a composição/agregação, a qual nos permite que um objeto

contenha outros objetos criando complexos relacionamentos. Um dos relacionamentos mais

instigantes que a composição/agregação provê é a possibilidade de criar um hierarquia de

objetos, contendo relações todo-parte, de modo que possamos tratar exatamente da mesma

forma objetos individuais, bem como objetos compostos.

uses clCliente; // declarando a unit que contem a class TCliente

Type

TPedido = class(TObject)

private

{ atributos / métodos privados }

protected

_codigo: String;

_cliente: TCliente; // um pedido possui um cliente (*-1), associação

public

constructor Create;

Property Codigo: String read getCodigo write setCodigo;

Property Cliente: TCliente read getCliente write setCliente;

end;

Page 7: Orientação a Objetos no Delphi - Por onde começar (I)

Interface

A declaração de uma Interface define um “contrato” a ser seguido para o desenvolvimento de

uma classe. Resumidamente a interface estipula que todas as classes vinculadas a ela deverão

implementar todos os métodos declarados pela interface. Com isso obtemos um determinado

grau de padronização, aumentando a versatilidade do modelo de classes de um modo geral. A

definição de uma interface é realizado utilizando a palavra reservada interface.

Type

ICalculadora = Interface // nenhuma implementação deve ser definida aqui

public

function getResult(): Double;

procedure setResult(Value: Double);

procedure calculate(x, y: Double);

property Result: Double read getResult write setResult;

end;

TCalculadora = class(ICalculadora)

protected

_resultado: Double

public

function getResult(): Double;

procedure setResult(Value: Double);

procedure calculate(x, y: Double);

end;

implementation

// implementação dos métodos definidos na Interface

Notação UML

A orientação a objetos possui uma forma especial de modelagem via diagramas, tal qual como

vemos na área de banco de dados com o DER (Diagrama Entidade-Relacionamento); chamado

de UML (Unified Modeling Language – Linguagem de Modelagem Unificada). Seu objetivo é

permitir que, através de diagramas simples, toda a lógica de interações entre os objetos que

compõe o nosso sistema possa ser representada.

Na UML encontramos diversos tipos de diagramas, um para cada finalidade, porém o mais

importante deles é o diagrama de classe, do qual modelamos e definimos os relacionamentos

entre as classes de uma aplicação. Para a modelagem UML podemos utilizar o software Judy

Community (http://jude.change-vision.com/jude-web/product/community.html).

Page 8: Orientação a Objetos no Delphi - Por onde começar (I)

Figura 1 – Modelagem do diagrama de classe simplificado através do Judy.

2. Vantagens e desvantagens da Orientação a Objetos

Orientação a objetos é difícil

O paradigma orientado a objetos introduz conceitos que estão presentes no mundo real,

porém para aqueles que vem da programação estrutural, os conceitos podem não ficar tão

claros de imediato. Aproveitar o que a orientação a objetos pode lhe proporcionar por

completo poderá ser mais trabalhoso inicialmente, porém oferece uma maior organização de

código, que geralmente facilita o trabalho da equipe de desenvolvimento, com uma clara visão

sobre as responsabilidades de cada classe dentro do contexto de uma aplicação; uma maior

reutilização de código através de heranças e associações entre objetos (sem ficar realizando o

famoso ‘CRTL+C’ e ‘CRTL+V’, como de costume no paradigma estrutural – o que está mais

propenso a erros), oferecendo um considerável ganho de produtividade.

A arquitetura de uma aplicação OO se mostra mais organizada a tornando flexível. A

flexibilidade aqui significa realizar alterações futuras de forma fácil. A organização do código-

fonte irá definir a qualidade de uma aplicação, permitindo construir abstrações, que com a

programação estrutural ficaria muito difícil de implementar e estender.

Projetos orientados a objetos são lentos

Os projetos de software orientado a objetos tendem a ser mais complexos, pois envolvem uma

grande gama de fatores, o que pode aparentar uma certa lentidão ao perceber uma série de

heranças e associações entre objetos, quando todos os objetos são instanciados em memória

Page 9: Orientação a Objetos no Delphi - Por onde começar (I)

ao efetuar, por exemplo, uma operação como uma visualização de pedido de venda.

Analisando pela lógica, pode ficar evidente que aplicações compostas por várias classes com

foco nas unidades que realizam o processo e não no fluxo de execução (paradigma procedural)

podem vir a ser mais lentos, porém não foi realizado uma experiência real, medindo o tempo

de execução em uma aplicação estruturada e outra orientada a objetos, o que seria

interessante para medir o desempenho de cada uma.

É valido observar que podemos inicializar objetos na memória por demanda, ou seja, instanciá-

los somente quando realmente formos utilizar os mesmos. Esta aparente desvantagem da OO

pode ser recompensada por uma maior facilidade de manutenção, reutilização de código e

flexibilidade do projeto de software. Analisando por outra visão, OO pode ser mais lenta que o

paradigma procedural que por sua vez é mais lento que Assembly. Então, será a linguagem

Assembly a real solução para a aparente lentidão na aplicação de software ? A aparente

lentidão é nosso real problema e de nossos clientes ? Pense nisso!

Modelo Orientado a objetos e bancos de dados relacionais

Um dos problemas que a orientação a objetos encontra é a persistência de objetos em banco

de dados relacionais, ou seja, em tabelas. Neste tipo de bancos de dados não conseguimos

persistir objetos por inteiro, sem que ocorra uma serialização (colocar os atributos e seus

respectivos valores de forma que fiquem em série, de forma seqüencial) do mesmo para que

cada atributo seja mapeado para uma coluna da tabela no banco de dados relacional. O

processo de serialização de objetos quando feito manualmente sem o auxilio de um

framework que possua este propósito é custoso e demorado. Então, qual é a melhor forma e

com um certo grau de produtividade e automatização poderíamos serializar objetos e efetuar

a persistência?

O ambiente Delphi a partir da versão 8, intitulado Delphi 8 for .NET introduziu o framework

.Net que suporta o OR/M NHibernate (http://nhibernate.org) que é uma framework que

realiza o mapeamento de classes de negócio para tabelas relacionais, automatizando assim

tarefas repetitivas de forma elegante, nos poupando da preocupação de como serializar e

recuperar objetos. A vantagem que um OR/M proporciona é a independência de banco de

dados, podendo ser utilizado qualquer banco de dados suportado pelo framework, tornando

as classes de negócios independentes e sem praticamente nenhuma sentença SQL declarada

no código-fonte, pois o OR/M gerencia as instruções SQL necessárias. Com isso obtemos mais

tempo para concentrar esforços no que realmente é importante: as classes de negócio de

nossa aplicação!

Maior reutilização de código

Ao realizar a modelagem de diversas classes, que geralmente interagem entre si através das

associações, construímos aplicações completas para um determinado domínio. A criação de

diversas instâncias de objetos de uma mesma classe proporciona um grande exemplo de

reutilização de código; observamos também que com a mesma modelagem (classe) podemos

obter classes mais especialistas através da herança. Uma maior reutilização de código é obtida

através da criação de componentes de software e da aplicação de Design Patterns.

Page 10: Orientação a Objetos no Delphi - Por onde começar (I)

Testes unitários (automação de testes)

Ao desenvolver um software, antes da entrega para o cliente é necessário realizar uma bateria

de testes para verificar a integridade e a qualidade do software do qual estamos oferecendo. O

teste unitário é uma modalidade de teste do qual verifica-se a menor unidade do projeto de

software, que pode ser identificado como um método, uma classe ou até mesmo um objeto.

O teste ocorre de maneira isolada, definindo um conjunto de estímulos (métodos), e dados de

entrada e saída associados a cada estímulo implementado pelo próprio desenvolvedor antes

ou depois da modelagem do método ou classe. No ambiente Delphi encontramos o framework

DUnit (http://dunit.sourceforge.net) que é uma ferramenta open-source para testes de

unidade. O principal motivo para utilizar o DUnit integrado com o Delphi é a economia de

tempo gasto em cada teste, a qualidade dos testes que podemos executar em nossas unidades

de código, promovendo assim um melhor design da aplicação. Ao invés de colocar vários

break-points na unit e ir “debugando manualmente” e verificando o valor de cada variável ou

expressão, podemos escrever diversos estímulos e verificar se o resultado é o esperado.

Figura 2 – Testes unitários sendo executados de forma independente da aplicação principal.

Padrões de Projetos (Design Patterns)

Os padrões de projetos foram propostos em 1994 por Erich Gamma, John Vlissides, Ralph

Johnson e Richard Helm – conhecidos como GoF (Gang of Four). Tem por finalidade descrever

soluções customizadas para problemas recorrentes no desenvolvimento de software orientado

Page 11: Orientação a Objetos no Delphi - Por onde começar (I)

a objetos. Com a crescente utilização do paradigma OO, surgiu a necessidade de desenvolver

software de maior qualidade – e com isso diversos padrões foram introduzidos e consolidados,

com o objetivo de aumentar a produtividade e reuso. Os padrões são organizados em: de

criação, estruturais e comportamentais; seu escopo pode abranger uma classe ou objeto.

Com a utilização de padrões de projetos não é necessário “re-pensar” em soluções para o

mesmo problema recorrente, basta utilizar um padrão que já foi amplamente utilizado por

várias empresas de desenvolvimento de software. Além disso definimos um padrão de

comunicação que é compartilhado por toda a equipe de desenvolvimento.

3. Conclusão

O paradigma orientado a objetos é uma evolução do processo de desenvolvimento estrutural e

está conquistando espaço em equipes de desenvolvimento de software, permitindo uma

maior organização de código, tornando os projetos de software flexíveis, ou seja, as alterações

futuras são realizadas de forma fácil, pois temos uma clara visão sobre as responsabilidades de

cada classe e suas interações. É notado um ganho de produtividade considerável através da

herança, permitindo o código ser extensível e reutilizável. Através do diagrama de classes que

a UML oferece temos uma documentação padronizada e simplificada do projeto de software, e

em grandes equipes de desenvolvimento o entendimento de determinada classe pode se

tornar tarefa fácil para quem estiver integrando uma nova equipe. A qualidade de software

pode ser é facilmente alcançado com a utilização da orientação a objetos através dos vários

tópicos mencionados no corpo deste artigo.

Esta primeira parte introduziu os conceitos da orientação a objetos no ambiente Delphi. Nos

próximos artigos iremos abordar a construção de uma aplicação básica de controle de

estoque, colocando em prática todos os conceitos abordados neste artigo.

Caso tenha alguma dúvida entre em contato comigo. Será um prazer ajudar.

Até a segunda parte da série sobre a orientação a objetos.