Design Pattern - Factory Method

nicolasdesouza

Nicolas de Souza

Posted on April 26, 2024

Design Pattern - Factory Method

Design Patterns, padrões de design ou até padrões de projeto, são um conjunto de soluções típicas para problemas comuns dentro do desenvolvimento de software.

São algoritmos?! Não. Um algoritmo é uma descrição detalhada de passos para realizar uma determinada tarefa. Um design pattern é mais alto nível que isso, expõe comportamentos e orientações a nível organizacional do código.

É importante salientar que diferente de funções e bibliotecas que encontramos e rapidamente incorporamos ao nosso código, implementar um padrão é muito mais do que isso, sendo necessário uma análise minuciosa dos relacionamentos existentes e dos possíveis ganhos que cada padrão poderá nos fornecer.

Há três grandes grupos dentro do estudo de padrões de projeto:

  1. Padrões criacionais
  2. Padrões estruturais
  3. Padrões Comportamentais

Vamos focar no primeiro e esmiuçar alguns pontos.

Padrões criacionais

A criação de objetos é intrínseco ao desenvolvimento de software, é normal que passemos diariamente por problemas que outros já passaram e assim podemos nos beneficiar do estudo de padrões, afim de não reinventarmos a roda sempre que nos depararmos com um novo problema.

Poderemos então abrir nossa caixa de ferramentas e encontrar algo que nos ajude.

Factory Method

Factory Method é um padrão criacional de projeto que fornece uma interface para criar objetos em uma superclasse, mas permite que as subclasses alterem o tipo de objetos que serão criados.

Talvez seja o padrão criacional mais simples de se entender, talvez você já até tenha usado esse padrão nos seus projetos e nem sabia que havia um nome para esta abordagem.

A ideia aqui é criar uma fábrica de objetos, sempre que precisarmos de um objeto específico poderemos usar esta fábrica e obter um objeto válido sem maiores dificuldades. Mas por que? Como? Quando?

Vamos dar um passo atrás...

Vamos pensar em uma faculdade, no primeiro semestre há apenas o curso de Engenharia Civil.


public class CivilEngineeringStudent
{
    public string Name {get; set;}
    public string DateOfBirth {get; set;}
    public int Duration {get; set;}
    public List<string> Courses {get; set;}

    public (string name_, DateTime DateOfBirth_)
    {
        name = name_;
        DateOfBirth = DateOfBirth_;
        Duration = 5;
        Courses.Add("Calculus I");
        Courses.Add("Programming I");
        Courses.Add("algebra");
    }
}

Enter fullscreen mode Exit fullscreen mode

Então quando queríamos criar seria só usar o new e pronto, teríamos um novo estudante. E estava tudo certo, até que em algum momento o CEO decidiu que agora teríamos também o curso de Biologia. E lá vamos nós construir um novo modelo de dados para vídeo


public class BiologyStudent
{
    public string Name {get; set;}
    public string DateOfBirth {get; set;}
    public int Duration {get; set;}
    public List<string> Courses {get; set;}

    public (string name_, DateTime DateOfBirth_)
    {
        name = name_;
        DateOfBirth = DateOfBirth_;
        Duration = 4;
        Courses.Add("Marina Life I");
        Courses.Add("Algebra");
        Courses.Add("Calculus I");
    }
}

Enter fullscreen mode Exit fullscreen mode

Mas pera aí, na hora de criar um novo estudante, vou precisar selecionar o tipo de post para então criar um objeto. Estou aumentando a complexidade... Há uma forma mais interessante de fazer isso, usando o Factory Method.

Vamos criar a interface graduation, e nossas classes CivilEngineeringStudent e BiologyStudent, irão herdar dela os seus dados.


public interface IGraduation 
{
    public string Name {get; set;}
    public string DateOfBirth {get; set;}
    public int Duration {get; set;}
    public List<string> Courses {get; set;}
    public void PrintStudent();
}

public class CivilEngineeringStudent : Graduation
{
    public (string name_, string DateOfBirth_)
    {
        name = name_;
        DateOfBirth = DateOfBirth_;
        Duration = 5;
        Courses.Add("Calculus I");
        Courses.Add("Programming I");
        Courses.Add("algebra");
    }

    public void PrintStudent()
    {
         Console.WriteLine($"Student of Civil Engineering - {this.name}")
    }

}
public class BiologyStudent : Graduation
{
    public (string name_, string DateOfBirth_)
    {
        name = name_;
        DateOfBirth = DateOfBirth_;
        Duration = 4;
        Courses.Add("Marina Life I");
        Courses.Add("Algebra");
        Courses.Add("Calculus I");
    }

    public void PrintStudent()
    {
         Console.WriteLine($"Student of Biology - {this.name}")
    }
}
Enter fullscreen mode Exit fullscreen mode

Mas só isso ainda não resolve nosso problema original, continuaria sendo necessário fazer duas chamadas diferentes, selecionando manualmente qual objeto seria criado em qual momento.

Para isso criaremos também uma classe abstrata chamada de Creator, que irá criar os objetos de acordo a nossa necessidade.

public abstract Creator 
{
    public abstract IGraduation FactoryMethod();
}

public class ConcreteCreator: Creator
{
    public override IConteudo GetGraduation(string graduation, string name, string DateOfBirth)  
    {
        switch(graduation)
        {
            case "Biology"
                return new BiologyStudent(name, DateOfBirth);
            break;
            case "Civil Engineering"
                return new CivilEngineeringStudent(name, DateOfBirth);
            break;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Agora podemos criar estudantes para os dois cursos como poderemos ver no código que segue. Vamos criar dois estudantes, uma de Biologia outro de Engenharia Civil.


var factory = new ConcreteCreator();

var studenteOfBiology = factory.GetGraduation("Biology", "Judith", "01/01/2003");

var studenteOfCivilEngineering = factory.GetGraduation("Civil Engineering", "Kirk W.", "01/01/1958");

List<IGraduation> students = new();

students.Add(studenteOfBiology);
students.Add(studenteOfCivilEngineering);

foreach(var student in students)
    student.PrintStudent();


Enter fullscreen mode Exit fullscreen mode

Prós e Contras

Prós

  • Baixo acoplamento
  • Auxilia a implementar os conceitos de SOLID, em especial:
    • Princípio de responsabilidade única
    • Princípio aberto/fechado

Contras

  • Aumento significativo da complexidade do código
💖 💪 🙅 🚩
nicolasdesouza
Nicolas de Souza

Posted on April 26, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

🔎Exploring Design Patterns: Adapter Pattern
designpatterns 🔎Exploring Design Patterns: Adapter Pattern

November 16, 2024

Understanding the Visitor Pattern in C#
designpatterns Understanding the Visitor Pattern in C#

November 7, 2024

Understanding the State Design Pattern P2
designpatterns Understanding the State Design Pattern P2

November 2, 2024

Understanding the State Design Pattern P3
designpatterns Understanding the State Design Pattern P3

November 2, 2024