Atualização do e-book: Mais padrões de design e princípios SOLID

No outono de 2022, lançamos o e-book Eleve o nível de seu código com padrões de programação de jogosjuntamente com um repositório do GitHub com código de amostra. Também lançamos uma série de tutoriais em vídeo de cinco partes para acompanhar o e-book e o projeto de amostra.
Recebemos ótimos comentários sobre esses recursos, e muitos de vocês pediram que abordássemos outros padrões de design. Obrigado por compartilhar seu feedback. Minha equipe e eu acompanhamos de perto seus comentários e realmente agradecemos.
Hoje, tenho o prazer de anunciar que uma edição atualizada do e-book, Level up your code with design patterns and SOLID, já está disponível, com uma versão atualizada do projeto de amostra de padrões de design, que você pode baixar na Unity Asset Store.
Tanto o livro eletrônico quanto o projeto de amostra agora são baseados no Unity 6 e incluem mais exemplos e padrões. O projeto de amostra também inclui mais recursos do UI Toolkit, inclusive um exemplo que demonstra a vinculação de dados, uma solicitação popular da comunidade.
Observação: O Unity 6 estará disponível ainda este ano. Se você quiser acompanhar os exemplos do guia e o projeto de demonstração que o acompanha, faça o download do Unity 6 Preview.

Antes de mergulhar no novo conteúdo do e-book, alguns de vocês que estão menos familiarizados com os conceitos podem se perguntar: Por que eu deveria aprender sobre padrões de design e como eles se encaixam no desenvolvimento de jogos Unity?
Voltando ao seu feedback, embora os fundamentos da programação orientada a objetos sejam familiares para muitos, a aplicação desses princípios em seu próprio código às vezes pode parecer abstrata e excessivamente acadêmica.
Pense da seguinte forma: Para cada problema de design de software que você enfrenta, inúmeros desenvolvedores já enfrentaram desafios semelhantes antes de você. Embora nem sempre seja possível pedir conselhos diretamente a eles, você pode aprender com as soluções deles por meio de padrões de design.
Os padrões de design oferecem soluções gerais para problemas comuns na engenharia de software. Eles não são modelos prontos para copiar e colar em seu código, mas sim ferramentas em sua caixa de ferramentas para usar quando necessário. Alguns padrões são mais intuitivos do que outros, mas cada um deles pode ser útil em cada contexto.
Criamos este guia para aqueles que são iniciantes em padrões de design ou que precisam apenas de uma atualização. Ele descreve cenários comuns no desenvolvimento de jogos em que esses padrões podem ser aplicados. Se estiver fazendo a transição de outra linguagem orientada a objetos, como Java ou C++, para C#, encontrará exemplos práticos de como adaptar esses padrões especificamente para Unity.
Em sua essência, os padrões de design são simplesmente ideias. Elas não se aplicam a todas as situações, mas, quando usadas corretamente, podem ajudá-lo a criar aplicativos escalonáveis. Integrá-los em seus projetos aumentará a legibilidade e a capacidade de manutenção do código. À medida que se familiarizar com esses padrões, você identificará oportunidades para otimizar seu processo de desenvolvimento.
Em resumo, nosso guia foi elaborado para elevar suas habilidades de codificação e criar projetos melhores na Unity, além de estabelecer um entendimento das práticas recomendadas gerais do setor que você pode levar consigo ao longo de sua carreira.

Vamos dar uma olhada nas novas adições importantes aos recursos de padrões de design:
Uma seção ampliada sobre como implementar os princípios SOLID
Os cinco princípios fundamentais do SOLID agora têm exemplos de códigos práticos implementados no projeto de amostra que são explicados no e-book. Como lembrete, SOLID é um acrônimo mnemônico para cinco fundamentos básicos do design de software - pense neles como cinco regras básicas a serem lembradas que podem ajudá-lo a manter os designs orientados a objetos compreensíveis, flexíveis e passíveis de manutenção.
Como um lembrete rápido, SOLID significa:
- Princípio da responsabilidade única: Uma classe deve ter apenas um motivo para mudar, o que significa que ela deve ter apenas um trabalho ou responsabilidade.
- Princípio aberto-fechado: As classes devem ser abertas para extensão, mas fechadas para modificação, permitindo que sejam estendidas sem alterar o código existente.
- Princípio de substituição de Liskov: Os objetos de uma superclasse devem poder ser substituídos por objetos de suas subclasses sem afetar a correção do programa.
- Princípio de segregação de interface: Os clientes não devem ser forçados a depender de interfaces que não usam. Ele promove a criação de interfaces específicas em vez de uma única interface de uso geral.
- Princípio de inversão de dependência: Os módulos de alto nível não devem depender de módulos de baixo nível, mas ambos devem depender de abstrações.

A principal conclusão de mergulhar nos exemplos é que seguir os princípios pode ajudá-lo a obter os seguintes benefícios no desenvolvimento de jogos:
- Legibilidade: Um código claro e bem organizado facilita a compreensão eficiente da funcionalidade do projeto. A adesão aos princípios SOLID pode melhorar a legibilidade do código; quando os padrões de código são consistentes, você aumenta a chance de uma colaboração tranquila entre os programadores de jogos de uma equipe.
- Escalabilidade: A implementação dos princípios SOLID promove a manutenção do código, o que é crucial para projetos que você deseja dimensionar. Ao aderir a esses princípios, as alterações feitas em uma parte da base de código têm menos probabilidade de introduzir problemas inesperados em outra parte. Essa abordagem garante que o código permaneça flexível e adaptável aos requisitos em evolução.
- Velocidade: Em última análise, os princípios SOLID contribuem para melhorar os fluxos de trabalho de desenvolvimento de jogos. O código modular, um aspecto fundamental enfatizado pelo SOLID, envolve a divisão dos sistemas em componentes menores e gerenciáveis. Essa abordagem modular facilita o teste, a depuração e a reutilização de código em projetos, reduzindo o tempo de desenvolvimento e aumentando a produtividade.

O livro eletrônico e o projeto atualizados incluem quatro novos padrões, elevando o total para 11. Aqui está um resumo rápido de cada um deles:
- Padrão de fábrica: Um caso de uso clássico é quando você tem powerups (como aumentos de velocidade, escudos ou vidas extras), que compartilham vários atributos, mas têm funcionalidades diferentes. Aqui, o padrão de fábrica pode ser usado para criar instâncias dessas diferentes classes de powerup derivadas de uma interface comum ou de uma classe base, permitindo a adição flexível de novos powerups sem modificar o código do cliente existente.
- Pooling de objetos: Alguns se referem a isso como uma técnica de otimização de desempenho em vez de um padrão de design. De qualquer forma, pense nisso como uma maneira de melhorar o desempenho reutilizando objetos em vez de criá-los e destruí-los com frequência. Em nossa cena de exemplo, você encontrará um exemplo de uma torre de canhão disparando grandes quantidades de balas em velocidade rápida. Em vez de instanciá-los (e limpá-los depois que serviram ao seu propósito com um custo significativo de desempenho), sempre usamos o padrão para reciclá-los repetidamente.
- Singleton: O singleton é provavelmente um dos padrões comuns no desenvolvimento de jogos - é provável que você já o esteja usando hoje. É útil se você precisar ter um objeto que coordene as ações em toda a cena. Por exemplo, você pode querer que um gerenciador de jogos em sua cena dirija o loop principal do jogo. No entanto, há algumas armadilhas a serem observadas ao usar o padrão singleton, que explicamos no guia.
- Padrão de comando: Você provavelmente já viu o padrão de comando em ação se jogou um jogo que usa a funcionalidade desfazer/refazer ou mantém o histórico de entrada em uma lista. É um padrão que pode ser aproveitado para um jogo de estratégia, por exemplo, em que o usuário pode planejar várias jogadas antes de executá-las na ordem em que a entrada foi fornecida.
- Padrão estadual: Isso permite que um objeto altere seu comportamento quando seu estado interno muda, o que simplifica o gerenciamento de comportamentos complexos dependentes do estado em personagens de jogos ou elementos da interface do usuário. Pense em um NPC inimigo que tenha comportamentos diferentes, como "ocioso", "patrulhando" ou "atacando", o que depende de diferentes cenários de jogo, como a posição do jogador no mapa.
- Padrão de observador: Esse padrão ajuda você a implementar um sistema de eventos eficiente em que os objetos podem se inscrever e reagir a eventos dinamicamente. Um caso de uso é o de um jogador que coleta munição em um jogo de ação que aciona diferentes eventos, como a reprodução de um som, a atualização da interface do usuário e a reprodução de uma animação.
- Model View Presenter (MVP): Em sua essência, esse padrão trata de desacoplar a exibição do estado do estado real, permitindo um design reativo em que as exibições são atualizadas automaticamente em resposta às alterações do modelo, o que o torna um padrão comum na programação da interface do usuário. O modeloé o dado, a visualizaçãoé a interface do usuário e o apresentadoré um mediador que lida com a lógica da visualização e sincroniza os dados do modelo.
- Modelo-Vista-VistaModelo (novo): Como o nome indica, esse padrão está relacionado ao padrão MVP, mas o expande com a adição de vinculação de dados em tempo de execução, o que simplifica a atualização dos elementos da interface do usuário. Em nosso exemplo, aproveitamos o novo recurso de vinculação de dados do UI Toolkit e do Unity 6 Preview.
- Padrão de estratégia (novo): Esse padrão define uma família de algoritmos encapsulando cada um deles, para torná-los intercambiáveis, permitindo que o algoritmo varie independentemente dos clientes que o utilizam. Esse é um padrão útil para implementar diferentes comportamentos de movimento na IA do jogo, por exemplo.
- Padrão Flyweight (novo): Use esse padrão para otimizar o uso da memória, compartilhando o máximo possível de dados com objetos semelhantes. A ideia básica é centralizar os dados compartilhados entre os objetos.
- Dirty Flag (Novo): Esse padrão é útil para otimizar o desempenho, marcando os objetos como "sujos" quando são alterados, para que sejam recalculados ou atualizados somente quando necessário. Esse padrão pode ajudá-lo a gerenciar atualizações caras em loops de jogos ou em alguns casos de renderização da interface do usuário.

O projeto de amostra reflete o livro eletrônico, demonstrando cada um dos 11 padrões em ação. Você pode fazer o download do projeto na Asset Store e acompanhar as cenas correspondentes para ver esses padrões aplicados em cenários do mundo real. Observe que o projeto requer o Unity 6 Preview ou posterior.
Antes de iniciar o projeto, há algumas dicas úteis que você deve ter em mente.

Comece com a cena do Bootstrap. Essa cena configura a demonstração e fornece acesso ao menu principal (você pode saber mais sobre o conceito de SceneBootStrapper no e-book). No menu principal, você pode navegar até a amostra apropriada. Cada cena demonstra um princípio ou padrão de design SOLID diferente.

Observe que pode haver pequenas diferenças entre o projeto de amostra e os exemplos de código no guia. Para aumentar a clareza e a legibilidade, alguns exemplos apresentam código simplificado, como campos públicos.
Sua equipe pode preferir um estilo de codificação diferente das convenções usadas neste guia ou no projeto de amostra. Recomendamos criar um guia de estilo C# adaptado às suas necessidades específicas e segui-lo de forma consistente em toda a equipe. Confira nosso e-book sobre como criar seu próprio guia de estilo para saber mais.
Considere os exemplos fornecidos e determine qual padrão de design se alinha melhor às necessidades de seu projeto. À medida que se familiarizar com esses padrões, você descobrirá o potencial deles para simplificar e melhorar seu fluxo de trabalho de desenvolvimento.
Tanto o e-book quanto o projeto de amostra sobre o uso de padrões de design estão disponíveis para download gratuito:
Boa codificação!