programe voltado a interface nao a implementacao

Upload: vinicius-almeida

Post on 19-Feb-2018

218 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/23/2019 Programe Voltado a Interface Nao a Implementacao

    1/7

    C

    Tpicos de Orientao a Objetos

    Um bom design de soware visa a uma arquitetura flexvel que permita futuras

    alteraes, facilite a produo de cdigo organizado e legvel, maximizando seu

    reaproveitamento. Todo o paradigma da orientao a objetos, seus princpios e

    boas prticas procuram trazer esses benefcios para o design.

    Ao pensar no sistema como um todo, outras questes de mais alto nvel sur-

    gem, em especial aquelas que tratam da forma como os objetos se relacionam

    e sua organizao dentro e entre sistemas. Ao relacionar dois objetos distintos,

    deve-se levar em conta as boas prticas que sero discutidas nesse captulo, como

    a diminuio do acoplamento entre objetos.

    .. P,

    Ao trabalhar com colees, escolher a implementao certa para cada caso uma

    tarefa difcil. Cada uma delas, como ArrayList, LinkedListou HashSet, me-

    lhor para resolver determinas categorias de problemas. Pode ser muito arriscado

    ArqDesignSoftware_BOOK indb 47ArqDesignSoftware_BOOK.indb 47 12/11/2011 14:48:3612/11/2011 14:48:36

  • 7/23/2019 Programe Voltado a Interface Nao a Implementacao

    2/7

    48

    Captulo 3. Tpicos de Orientao a Objetos

    escrever todo o cdigo da aplicao dependente de uma deciso antecipada. Ape-

    sar disso, grande parte dos desenvolvedores opta por sempre utilizar ArrayList

    desde o incio sem critrio algum.

    Considere um DAO de funcionrios que pode listar o nome de todos que

    trabalham em determinado turno, devolvendo um ArrayListcom os nomes:

    public classFuncionarioDao {

    publicArrayList buscaPorTurno(Turno turno) { ... }

    }

    E um cdigo que precisa saber se determinado funcionrio esteve presente,

    efetuando uma busca simples na lista devolvida:

    FuncionarioDao dao = newFuncionarioDao();

    ArrayList nomes = dao.buscaPorTurno(Turno.NOITE);

    booleanpresente = nomes.contains(Anton Tcheckov);

    Mas a busca com containsem um ArrayList, em termos computacionais,

    bastante custosa. Poderamos utilizar outras alternativas de coleo, trocando o

    retorno de ArrayListpara HashSet, por exemplo, pois sua operao contains

    muito mais eficiente computacionalmente, usando internamente uma tabela

    de espalhamento (hash table). Para poucos funcionrios, a diferena imper-

    ceptvel, porm, medida que a lista aumenta, a diferena de desempenho entre

    um ArrayListe umHashSetse torna mais clara, e at mesmo um gargalo de

    performance.

    O problema em realizar uma mudana como esta, de implementao, que

    todo cdigo que usava o retorno do mtodo comoArrayListquebra, mesmo que

    s usssemos mtodos que tambm existem definidos em HashSet. Seria preciso

    alterar todos os lugares que dependem de alguma forma desse mtodo. Alm detrabalhoso, tarefas do tipo search/replaceso um forte sinal de cdigo ruim.

    H esse acoplamento sinttico com a assinatura do mtodo, que consegui-

    mos resolver olhando os erros do compilador. Mas sempre h tambm informa-

    es semnticas implcitas na utilizao desse mtodo, e que no so expostos

    atravs da assinatura. Um exemplo de acoplamento semntico est em depender

    da informao de que uma Listpermite dados duplicados, enquanto um Set

    garante unicidade dos elementos. Como problemas no acoplamento sinttico

    so encontrados em tempo de compilao, os semnticos somente o so em

    ArqDesignSoftware_BOOK indb 48ArqDesignSoftware_BOOK.indb 48 12/11/2011 14:48:3612/11/2011 14:48:36

  • 7/23/2019 Programe Voltado a Interface Nao a Implementacao

    3/7

    3.1. Programe voltado interface, no implementao

    49

    execuo, da um motivo da importncia de testes que garantam o comporta-

    mento esperado.

    O grande erro do mtodo buscaPorTurnoda classe FuncionarioDao foi

    atrelar todos os usurios do mtodo a uma implementao especfica de Collec-

    tion. Desta forma, alterar a implementao torna-se sempre muito mais custoso,

    caracterizando o alto acoplamentoque tanto se procura evitar.

    Para minimizar esse problema, possvel usar um tipo de retorno de mtodo

    mais genrico, que contemple diversas implementaes possveis, fazendo com que

    os usurios do mtodo no dependam em nada de uma implementao especfica.

    A interface Collection uma boa candidata:

    public classFuncionarioDao {

    publicCollection buscaPorTurno(Turno turno) { ... }

    }

    Com o mtodo desta forma, podemos trocar a implementao retornada sem

    receio de quebrar nenhum cdigo que esteja invocando buscaPorTurno, j que

    ningum depende de uma implementao especfica. Usar interfacesJava um

    grande benefcio nestes casos, pois ajuda a garantir que nenhum cdigo dependa

    de uma implementao especfica, pois interfaces no carregam nenhum detalhe

    de implementao.

    Repare que possvel optar ainda por outras interfaces, como List(mais

    especfica) e Iterable(menos especfica). A escolha da interface ideal vai de-

    pender do que voc quer permitir que o cdigo invocador possa utilizar e realizar

    na referncia retornada. Quanto menos especfica, menor o acoplamento e mais

    possibilidades de diferentes implementaes. Em contrapartida, o cdigo cliente

    tem uma gama menor de mtodos que podem ser invocados.

    Algo similar tambm ocorre para receber argumentos. Considere um mtodo

    que grava diversos funcionrios em lote no nosso DAO:

    public classFuncionarioDao {

    public voidgravaEmLote(ArrayList funcionarios) { ... }

    }

    Receber precisamente ArrayList como argumento tem pouca utilidade; ra-

    ramente necessitamos que uma coleo seja to especfica assim. Receber aqui um

    Listprovavelmente baste para o nosso mtodo, e permite que o cdigo invocador

    passe outras colees como argumento. Podemos ir alm e receber Collection

    ArqDesignSoftware_BOOK indb 49ArqDesignSoftware_BOOK.indb 49 12/11/2011 14:48:3612/11/2011 14:48:36

  • 7/23/2019 Programe Voltado a Interface Nao a Implementacao

    4/7

    50

    Captulo 3. Tpicos de Orientao a Objetos

    ou, ainda, Iterable, caso nossa necessidade seja apenas percorrer os elementos. A

    escolha de Iterable, neste caso, permitiria o maior desacoplamento possvel, mas

    limitaria o uso dentro do mtodo; no seria possvel, por exemplo, acessar a quanti-dade de elementos que essa coleo possui, nem os elementos de maneira aleatria

    atravs de um ndice. Devemos procurar um balano entre o desacoplamento e a

    necessidade do nosso cdigo. Esta a ideia do Princpio de Segregao de Interfaces:

    clientes no devem ser forados a depender de interfaces que no usam.1

    O desenvolvedor deve ter em mente que acoplar uma classe, que possui me-

    nos chances de alteraes em sua estrutura, com outra menos estvelpode ser

    perigoso.2Considere a interface List, que possui muitas razes para no mudar,

    afinal, ela implementada por vrias outras classes; se sofresse alteraes, todas

    as classes que a implementam teriam que ser alteradas tambm. Consideramos,

    ento, que ela altamente estvel, o que significa que ela raramente obrigar uma

    mudana nas classes que a utilizam (Figura 3.1).

    Figura 3.1 Interfaces so mais estveis por garantirem menores

    mudanas com quebra de compatibilidade.

    Uma implementao de lista, MeuProprioArrayList, feita pelo desenvolve-

    dor provavelmente mais instvelque a interface List, j que as foras que a im-

    ArqDesignSoftware_BOOK indb 50ArqDesignSoftware_BOOK.indb 50 12/11/2011 14:48:3712/11/2011 14:48:37

  • 7/23/2019 Programe Voltado a Interface Nao a Implementacao

    5/7

    3.1. Programe voltado interface, no implementao

    51

    pedem de mudar so fracas (no h outras classes utilizando essa implementao).

    Ou seja, uma classe acoplada a essa implementao de lista eventualmente pode

    ser obrigada a mudar por causa de alguma alterao em MeuProprioArrayList.

    Os frameworks e bibliotecas consagrados sempre tiram proveito do uso

    de interfaces, desacoplando-se o mximo possvel de implementaes. Tanto a

    Sessiondo Hibernate quanto a EntityManagerda JPA devolvem List nos

    mtodos que envolvem listas de resultados. Ao analisar a fundo as implemen-

    taes atuais de Sessione EntityManager do Hibernate, elas no retornam

    nem ArrayList, nem LinkedList, nem nenhuma coleo do java.util, e, sim,

    implementaes de listas persistentes de pacotes do prprio Hibernate.

    Isto possvel, novamente, pelo desacoplamento provido pelo uso das inter-faces. Alm disso, o retorno das consultas com JPA e Hibernate so List, para

    deixar claro ao usurio que a ordem importante. Manter a ordem de insero e

    permitir acesso aleatrio so caractersticas do contrato deListe so importantes

    para o resultado de consultas, pois podem definir uma ordenao (order by),

    uma tima justificativa para optar por uma interface mais especfica, e no usar

    Iterableou Collection.

    Nas principais APIs do Java, fundamental programar voltado interface.

    Ao usar java.io, evitamos ao mximo nos referenciar a FileInputStream,

    SocketInputStream, entre outras. O cdigo a seguir aceita apenas arquivos

    como streams:

    public classImportadoraDeDados {

    public voidcarrega(FileInputStream stream) { ... }

    }

    Desta forma, no possvel passar qualquer tipo de InputStream para a

    ImportadoraDeDados. Adotar esta limitao depende do cdigo dentro do m-

    todo carrega. Ao utilizar algum mtodo especfico de FileInputStreamqueno esteja definido em InputStream, no h o que fazer para desacoplar o c-

    digo. Caso contrrio, esse mtodo poderia, e deveria, receber uma referncia a

    InputStream, ficando mais flexvel e podendo receber os mais diferentes tipos de

    streams, como argumento, que provavelmente no foram previamente imaginados.

    Utilize sempre o tipo menos especfico possvel.

    Repare que, muitas vezes, classes abstratas trabalham como interfaces, no

    sentido conceitual de orientao a objetos.3Classes abstratas possuem a vantagem

    de se poder adicionar-lhes um novo mtodo no abstrato, sem quebrar o cdigo

    ArqDesignSoftware_BOOK indb 51ArqDesignSoftware_BOOK.indb 51 12/11/2011 14:48:3812/11/2011 14:48:38

  • 7/23/2019 Programe Voltado a Interface Nao a Implementacao

    6/7

    52

    Captulo 3. Tpicos de Orientao a Objetos

    j existente. J com o uso de interfaces(aqui, pensando na palavra-chave do Java),

    a adio de qualquer mtodo acarretar a quebra das classes que a implementam.

    Como interfaces nunca definem nenhuma implementao, a vantagem que ocdigo est sempre desacoplado de qualquer outro que as utilize. Isso muda com

    os polmicos extension methodsdo Java 8, permitindo escrever uma implemen-

    tao padro nas interfaces, possibilitando suas evolues, ao mesmo tempo que

    minimiza a quebra de compatibilidade.

    Os mtodos load(InputStream), da classe Properties, e fromXML

    (InputStream), do XStream, so timos exemplos de cdigo que no depen-

    dem de implementao. Podem receber arquivos dos mais diferentes streams:

    rede (SocketInputStream), upload HTTP (ServletInputStream), arquivos(FileInputStream), de dentro de JARs (JarInputStream) e arrays de byte ge-

    nricos (ByteArrayInputStream).

    AJava Database Conectivity(JDBC) outra API firmemente fundada no uso

    de interfaces. O pacote java.sqlpossui pouqussimas classes concretas. Sempre

    que encontramos um cdigo trabalhando com conexes de banco de dados, vemos

    referncias interface Connection, e nunca diretamente a MySQLConnection,

    OracleConnection, PostGreSQLConnection, ou qualquer outra implementao

    de um driver especfico, apesar de esta possibilidade existir.

    Referindo-se sempre a Connection, deixamos a escolha da implementao

    centralizada em um ou poucos locais. Desta forma, fica muito fcil trocar a im-

    plementao sem modificar todo o restante do cdigo. Isso ocorre graas ao de-

    sacoplamento provido pelo uso de interfaces.

    No caso do JDBC, essa escolha por uma implementao est centralizada

    na classe concreta DriverManager, que aqui age como uma factory. Ela decide

    por instanciar uma implementao especfica de Connectionde acordo com os

    parmetros passados como argumentos ao mtodo getConnectione conforme

    os possveis drivers previamente carregados.

    Connection connection =

    DriverManager.getConnection(jdbc:mysql://192.168.0.33/banco);

    Pode ser fcil enxergar as vantagens do uso das interfaces, mas bem mais

    difcil comear a utiliz-las extensivamente no seu prprio domnio. O uso exage-

    rado de reflection para invocar mtodos dependendo de algumas condies pode

    ser muitas vezes substitudo por interfaces. Assim, a deciso de qual mtodo in-

    vocar deixada para a invocao virtual de mtodo que o polimorfismo promove,

    ArqDesignSoftware_BOOK indb 52ArqDesignSoftware_BOOK.indb 52 12/11/2011 14:48:3812/11/2011 14:48:38

  • 7/23/2019 Programe Voltado a Interface Nao a Implementacao

    7/7

    3.2. Componha comportamentos

    53

    diminuindo bastante a complexidade e aumentando a manutenibilidade, alm de

    algum ganho de performance.4

    Isto ainda mais gritante com o uso da instruo switch, ou mesmo em um

    excessivo nmero de ifsencadeados; essa abordagem pode acoplar totalmente

    seu modelo, tornando necessrias mudanas frequentes nele toda vez que uma

    nova entidade for adicionada ao domnio.5

    Programe voltado interface, no implementao outro dos prncipios

    de orientao a objetos do livro Design Patterns,6,3abordado por meio de outros

    exemplos no seminal Dependency Inversion Principle, de Bob Martin.7

    .. C

    Um cdigo com poucas possibilidades de fluxos lgicos (branchesde execuo), ou

    seja, poucos caminhos de execuo, mais fcil de entender e manter. O exemplo

    a seguir mostra um processo de pagamento:

    public voidprocessa(Pagamento aPagar) {

    if(aPagar.isServico() && aPagar.getValor() > 300) {

    impostos.retem(aPagar.getValor() * TAXA_A_RETER); } else if(aPagar.isProduto()) {

    estoque.diminui(aPagar.getItem());

    }

    conta.executa(aPagar);

    if(aPagar.desejaReceberConfirmacao()) {

    emails.enviaConfirmacao(aPagar);

    }

    }

    Apesar de simples, existem seis possibilidades diferentes de execuo do m-

    todo, alm de ele misturar diversos comportamentos que no possuem relao,

    isto , responsabilidades diferentes para uma nica classe: impostos, estoques,

    transferncias e e-mails.

    Tal comportamento pode ser composto por diversas partes menores e, para

    tanto, refatoraes pequenas podem ser executadas. A mais simples seria a ex-

    trao de quatro mtodos, uma soluo que simplifica o cdigo atual, mas no

    aumenta sua coeso.