Ao escrever código orientado a objetos, devo sempre seguir um padrão de design?

37

Existe um padrão de design concebível para qualquer programa orientado a objetos? Eu pergunto isso porque recentemente vi uma implementação de uma Doorclasse com a Lock. Fazia parte de um teste e a resposta dizia que o código está seguindo o padrão Null Object:

class Lock
{
public:
    virtual void close() = 0;
    virtual void open() = 0;
    virtual bool is_open() const = 0;
    virtual ~Lock() { }
};

class DummyLock
    : public Lock
{
private:
    DummyLock();
    DummyLock(const DummyLock&) = delete;
    DummyLock& operator=(const DummyLock&) = delete;

private:
    void close() { }
    void open() { }
    bool is_open() const { return true; }

public:
    static DummyLock m_instance;
};

class Door
{
public:
    Door() : m_lock(DummyLock::m_instance) { }
    Door(Lock &lock) : m_lock(lock) { }

public:
    Lock& get_lock() const { return m_lock; }

private:
    Lock &m_lock;
};

Isso me fez pensar: esse código segue um bom padrão de design, mesmo que a descrição seja tão simples (essa classe está projetando uma classe de porta com uma fechadura); portanto, se estou escrevendo um código mais complexo, sempre deve haver algum padrão de design que eu estou seguindo?

user2030677
fonte
51
Você acha que poderia falar inteiramente em idiomas? Não? Então você não deve construir seus programas juntando padrões de design.
Kilian Foth
4
No seu exemplo, o padrão de objeto Nulo é adicionado apenas para fins acadêmicos, não introduz "um bom design" nesse código.
Doc Brown
4
@djechlin: em outras palavras, usar a "duas palavras" padrão de design :)
Michael Shaw
11
O problema é que muitas pessoas acreditam que os padrões de design são um substituto para o pensamento e um substituto para a experiência (o que implica uma certa quantidade de tentativa e erro). Você não pode pegar um livro cheio de padrões de design e reuni-los como a Tinker Toys para produzir um aplicativo com tamanho e complexidade não triviais e qualidade decente. Mesmo programadores experientes geralmente precisam experimentar dois ou três projetos antes de encontrar um que funcione.
Daniel R Hicks

Respostas:

143

deve sempre haver algum padrão de design que estou seguindo?

Querido Deus NÃO!

Quero dizer, você pode ir em frente e dizer que qualquer código aleatório está seguindo algum padrão aleatório de XYZ, mas isso não é mais útil do que eu alegar ser o rei da cadeira do meu computador. Ninguém mais sabe realmente o que isso significa, e mesmo aqueles que sabem não respeitarão exatamente minha afirmação.

Os padrões de design são uma ferramenta de comunicação para que os programadores possam dizer a outros programadores o que foi feito ou o que deve ser feito sem gastar muito tempo se repetindo. E como são coisas que surgem várias vezes, são conceitos úteis para os programadores aprenderem "ei, fazer XYZ sempre parece surgir porque é bom / útil".

Eles não substituem a necessidade de você pensar por si mesmo, de adaptar os padrões do problema único à sua frente ou de lidar com todas as coisas inevitáveis ​​que não se encaixam em bons baldes.

Telastyn
fonte
5
Seu primeiro parágrafo é parte de como eu responderia a isso. Algo se torna um padrão quando é repetido. Se for repetido várias vezes para exigir comunicação, é um Padrão e se beneficia de um nome. Alguns até argumentam que um padrão só se desenvolve porque falta alguma abstração. A busca de padrões é o caminho para a infâmia, como membro do culto de carga.
Magus
11
@ Cerad: Claro, desde que você prometa não escrever aulas de Deus também!
precisa saber é o seguinte
9
John Doe - Engenheiro Técnico, código genérico do macaco e rei da sua cadeira do computador
HJK
11
Indiscutivelmente, um design deve usar padrões quando apropriado e as classes devem ser nomeadas como tal. Eles são uma ferramenta importante. Ter medo de the_cult(tm) é igualmente perigoso.
Gusdor
25
Ótima resposta! Minha única crítica é que o "Querido Deus NÃO!" não é grande o suficiente.
precisa saber é o seguinte
37

Não.

Isto é o que a Gang of Four (que originalmente popularizou os padrões de design) tinha a dizer sobre isso em seu livro :

"Nenhuma discussão sobre como usar padrões de design estaria completa sem poucas palavras sobre como não usá-los. Os padrões de design não devem ser aplicados indiscriminadamente. Frequentemente, eles alcançam flexibilidade e variabilidade introduzindo níveis adicionais de indireção e isso pode complicar um design. e / ou custam algum desempenho. Um padrão de design só deve ser aplicado quando a flexibilidade que ele oferecer for realmente necessária ".

O exemplo que você mostra não faz muito de nada (não acho que foi feito, acho que foi apenas um exemplo). Por si só, ele não precisa do padrão de objeto nulo. No contexto de um programa maior, pode ser.

A abordagem errada é supor que, apenas porque foi rotulado como "padrão de design", ele deve ser bom e, em seguida, procurar mais lugares para incluir mais padrões. Use-os quando eles se ajustarem ao programa e realmente resolverem um problema para você.

Michael Shaw
fonte
7
O livro é Design Patterns: Elements of Reusable Oriented Object Software, de Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides.
Developerwjk
4
+1 Para realmente citar a fonte dos padrões de design.
Pharap
29

se estou escrevendo um código mais complexo, sempre deve haver algum padrão de design que estou seguindo?

Não. Os padrões de design são exatamente isso: padrões nas relações entre objetos. Em outras palavras, relacionamentos que são usados ​​e reutilizados com frequência suficiente para que alguém dissesse "Ei, parece que estamos fazendo muito isso, vamos dar um nome". A lista de padrões de design não foi determinada de uma só vez no início do OOP e depois transmitida pelo GOF ! Eles foram descobertos e, eventualmente, documentados, e depois popularizados pelo livro.

Dito isso, grande parte dos benefícios dos padrões de design é que eles facilitam o pensamento sobre o design de software em um nível superior. Eles permitem que você deixe de se preocupar com os detalhes da implementação e pense mais sobre o cenário geral. Nesse sentido, eles o libertam das minúcias, mas também podem limitá-lo da mesma maneira que o modo como você se expressa pode ser limitado pelas palavras que conhece. Assim, pode chegar um momento em que não é um padrão de design para a maioria do que você faz simplesmente porque os padrões que você sabe que são os termos em que você pensa. Mantenha os olhos abertos para os casos em que você possa estar abusando de um padrão e onde possa precisar pensar mais profundamente sobre as melhores maneiras de fazer as coisas.

Além disso, saiba que, na prática, você geralmente não implementa um determinado padrão de design, mas reconhece o padrão em algum código existente, como uma estrutura de objeto. O conhecimento sobre padrões de design comuns facilita muito a aprendizagem de como uma estrutura se destina a ser usada, pois é possível ver os relacionamentos entre as classes nos termos que você já entende.

Caleb
fonte
10

Os padrões de design têm duas vantagens

  1. Eles são fáceis de descrever para outros desenvolvedores, porque as pessoas geralmente concordam com os padrões.
  2. Eles tendem a ter sido espancados pelos nossos antecessores, de modo que seus pontos fortes e fracos são bem compreendidos.

Os objetivos de todo programa devem ser

  1. Funciona. Ele precisa fazer qualquer que seja o objetivo final ou não importa quantos padrões de design você usa. Os padrões de design do OO facilitam a divisão do problema em bits fáceis de entender, facilitando a prova de que funciona.
  2. É fácil de ler. É aqui que os padrões de design são bons. Os problemas OO que eles resolvem são complicados. Se você resolvê-los de uma maneira "padrão", é mais fácil para o próximo desenvolvedor
  3. É fácil crescer. Quase 0 programas modernos terminam onde todos planejaram. Todo programa cresce após seu lançamento inicial. Os padrões de OO são conhecidos por serem curiosamente bons em crescer.

Dito isso, observe que todas as referências aos padrões de design de OO são "elas são boas no trabalho". Eles não são perfeitos, mas preenchem um nicho com muita eficácia. Use-os quando eles trabalham, evite-os quando não o fizerem.

Como exemplo, de "código complexo", como você mencionou na sua pergunta, use uma linguagem de script que eu escrevi. A maior parte é OO com padrões de design em todos os lugares. No entanto, quando se tratava de escrever o coletor de lixo, deixei sem cerimônia todas as pretensões de OO, porque as coisas específicas que eu precisava fazer eram mais bem modeladas como boas e antigas molduras de bits. Não existe um padrão OO em toda a coisa até escrever finalizadores, onde mais uma vez o OO começou a ser um modelo útil novamente. Sem pompa nem circunstância, o código repentinamente voltou a usar as técnicas OO novamente.

Use padrões de design sempre que eles melhorarem seu produto; evite-os quando piorarem o seu produto.

Cort Ammon
fonte
2
Eu acho que a última frase deve estar no topo em negrito ou como um resumo.
Pharap
5

Vou reverter um pouco a tendência, porque a resposta é mais sutil do que outras respostas. Toda classe que você escreve não deve empregar um padrão de design, mas a maioria dos programas não triviais que você escreve provavelmente deveria.

Um programa não trivial sem nenhum padrão de design indica:

  • Seu programa é tão exclusivo que nenhuma parte é semelhante aos problemas comuns que os programadores já enfrentaram antes. Ou
  • Seu programa contém esses problemas comuns, mas você os resolveu de uma maneira melhor que ninguém pensou antes.

Ambos os cenários são altamente improváveis, sem ofensas.

Isso não significa que o padrão de design deve guiá-lo, ou que você deve inseri-lo indiscriminadamente, porque acha que ficará ruim se não o fizer. O padrão de design errado é pior que nenhum.

O que isso significa é que você deve considerar a falta de padrões de design em seu programa como um cheiro de código. Algo que faz você dar uma segunda olhada e reavaliar se seu projeto não puder ser mais limpo. Se nesse ponto você decidir deixar os padrões de design fora de um programa, isso deve ser uma decisão deliberada e informada, não por acaso.

Por exemplo, você não diz: "Preciso modelar uma porta e uma fechadura, que padrão de design devo usar?" No entanto, se você o projetou primeiro sem usar nenhum padrão de design, você deve solicitar algo mais tarde: "Eu tenho muitas verificações nulas nesse código, será que há um padrão de design que possa ajudar a gerenciá-las"?

Veja a diferença? É uma distinção sutil, mas importante.

Karl Bielefeldt
fonte
5
Existem muitos problemas mais comuns (e suas soluções comuns) do que padrões de design. Os padrões de design são um subconjunto catalogado de soluções OO comuns - não o conjunto de todas as soluções comuns.
Michael Shaw
11
Você poderia definir o que você quer dizer com 'não trivial'? Fiquei com a impressão de que o termo 'não trivial' era subjetivo.
Pharap
11
É subjetivo. Quero dizer, o tipo de programa que você escreveria em uma equipe no trabalho, exigindo vários mantenedores continuamente.
Karl Bielefeldt
Se você tiver sorte o suficiente para ver seu problema posteriormente. Cheques nulos, com certeza. Vulnerabilidades de segurança? De que outras maneiras traiçoeiras o programa ficará em manutenção? Problemas que apenas o próximo engenheiro descobrirá? Muito mais nojento.
precisa saber é o seguinte
"Preciso modelar uma porta e trancar, qual deve ser a interface? O desempenho fará parte do contrato? Devo usar um serviço ou biblioteca? Como os recursos serão repassados?" todos devem ser solicitados e você deve ter respostas que são basicamente consideradas como padrões de design.
precisa saber é o seguinte
4

Pergunta quebrada. Deixe-me dar uma nova definição de padrão de design que iria desfazer muitos danos liberados pelo GoF: um padrão de design é uma boa prática de codificação . É isso aí.

Qualquer módulo razoavelmente complexo terá vários padrões de design. Sempre que você armazena em cache, provavelmente é um padrão de peso mosca, mas não vou revogar o seu grau de programação se você não chamar isso. Sempre que você tem um retorno de chamada, está em algum tipo de evento / incêndio / padrão de retorno de chamada. etc. Se você tem a palavra "estático", possui um singleton. Se você possui um construtor estático, possui um padrão de fábrica. Se um recurso é passado para o seu módulo, você está usando injeção de dependência.

"Padrão de design" é um termo quebrado pouco popularizado pelo GoF, que faz parecer que todos os padrões estão no mesmo nível ou você deve usar o médico recomendado de 3 a 5 por turma. Sempre que você faz algo certo que alguém fez certo, é um padrão de design . UMAfor(;;) é um padrão comum usado para representar um loop infinito, por exemplo.

Você não deve tentar aprender vários padrões de design. O conhecimento de programação não é indexado pelos padrões de design! Em vez disso, você deve aprender a escrever um bom código lendo livros, blogs e participando de conferências em seu campo. Por exemplo, se você já está usando injeção de dependência, mas não a rotulou, pode se beneficiar de sempre usar DI ou usar uma estrutura de IoC. Ou, se você estiver tentando codificar corretamente em eventos e retornos de chamada, aprenda Haskell para se familiarizar com os padrões de design funcional e isso se torna fácil.

E se toda a sua turma lê como algo importante que alguém fez corretamente, por que você está reinventando a roda? Basta usar as coisas deles.

djechlin
fonte
2
Em que idioma é for(;;)idiomático? Esse provavelmente não é o melhor exemplo de algo que alguém fez "certo".
Telastyn
11
@Telastyn C, C ++, Java, Javascript, C #.
precisa saber é o seguinte
2
Eu nunca vi ninguém preferem que mais while(true)(ou while(1)) em C, C ++, Java ou C # nos meus 20 anos de programação.
Telastyn
11
@Telastyn stackoverflow.com/a/2611744/1339987 fwiw Comecei a preferir while (true) porque parece mais legível para mim.
precisa saber é o seguinte
11
Eu sempre uso para (;;). Nenhuma razão em particular, eu li em algum lugar provavelmente. Eu gosto do fato de não haver variáveis ​​ou constantes envolvidas. Enfim, @Telastyn agora você conheceu alguém .
Ant
0

Você deve sempre seguir os princípios de design do OO (por exemplo, modularidade, ocultação de informações, alta coesão etc.). Os padrões de design são um nicho relativamente refinado dos princípios de design de OO, especialmente se você considerar o princípio KISS .

Padrões são soluções para problemas comuns de design. Esses problemas vêm de um dos dois lugares (ou uma mistura de ambos): o espaço do problema (por exemplo, software para gerenciar recursos humanos em uma empresa) e o espaço da solução . Um programa de OO é uma instância no espaço da solução (por exemplo, uma das muitas maneiras pelas quais você pode criar um programa de OO para facilitar o gerenciamento de RH).

Não é tão fácil saber quando usar um padrão. Alguns padrões são de baixo nível, mais próximos da codificação e do espaço da solução (por exemplo, Singleton, Null object, Iterator). Outros são motivados por requisitos no espaço do problema (por exemplo, Padrão de comando para suportar desfazer / refazer, Estratégia para suportar vários tipos de arquivos de entrada / saída).

Muitos padrões vêm da necessidade de suportar variações do software no futuro. Se você nunca precisar fazer essas variações, um padrão poderá ter um design excessivo. Um exemplo seria usar o padrão do adaptador para trabalhar com o banco de dados de RH externo existente. Você decide aplicar o Adapter porque o banco de dados atual funciona com Oracle e você pode querer oferecer suporte ao NoSQL no futuro. Se o NoSQL nunca chegar à sua organização, esse código do Adaptador poderá muito bem ser inútil. Veja YAGNI . O suporte para variações que nunca surgem é o uso indevido de um padrão de design.

Fuhrmanator
fonte
0

Padrões são soluções comuns para problemas comuns. Estamos sempre seguindo alguns padrões, os padrões do GoF abordam os mais recorrentes. Isso é ter um entendimento e uma abordagem compartilhados conhecidos pelos engenheiros de software.

Dito isto, minha resposta é não, mas sim, você está sempre seguindo algum padrão próprio. Como o GoF coloca corretamente -

O Padrão de uma pessoa é o bloco de construção primitivo de outra pessoa.

Ótima citação.

Syed Priom
fonte
este não parece oferecer nada substancial sobre pontos feitos e explicado em anteriores 7 respostas
mosquito
Bem. Note, eu fiz uma observação geral ... é aplicável aos Padrões de Design como uma discussão teórica.
perfil completo de Syed Priom
"Este site é sobre como obter respostas . Não é um fórum de discussão ..." ( tour )
gnat
Eu respondi a pergunta. Obrigado. Essa conversa termina aqui.
Syed Priom
@gnat é muito mais conciso, no entanto.
precisa saber é o seguinte
0

Quando estou escrevendo código, não planejo usar deliberadamente o maior número possível de padrões de design. Mas, suponho, subconscientemente, quando recebo um problema de codificação, um dos padrões de design parece se encaixar e eu apenas o uso. E às vezes nada se encaixa. O que é mais importante para mim é escrever um código que faça o trabalho e seja fácil de manter e crescer.

Aqui está um artigo sobre a aplicação dos princípios de OOD usando padrões de design e também possui exemplos de código (em C ++). Ele mostra como e quando aplicar alguns dos padrões de design para escrever código limpo.

água de rosas
fonte
2
Esse artigo foi escrito ontem; você é afiliado ao blog? Em caso afirmativo, divulgue essa afiliação .
Martijn Pieters