Back home

Padrões de design por tutoriais - O poder da OOP (parte 1)

Jornada dos Padrões de Design – O Poder do OOP 1

Padrões de design por tutoriais - O poder da OOP (parte 1)

Pré-requisitos — Esta série de blogs requer um nível intermediário de conhecimento em programação orientada a objetos. Você deve ter conhecimentos básicos sobre classe, objeto, construtor, herança, valor e tipo de referência. Um intermediário adquirirá conhecimento e os especialistas aprimorarão seu conhecimento lendo esta série do início ao fim. Pré-requisitos – Esta série de blogs requer conhecimento intermediário em programação orientada a objetos. Você deve ter um conhecimento básico de classes, objetos, construtores, herança, valor e tipos de referência. Um intermediário adquirirá conhecimento e um especialista aprimorará seu conhecimento lendo esta série do início ao fim.

Padrões de projeto são usados ​​para representar as melhores práticas adotadas pela experiente comunidade de desenvolvedores de software orientado a objetos. Os padrões de projeto são usados ​​para representar as melhores práticas adotadas por uma comunidade de desenvolvedores experientes de software orientado a objetos.

O padrão de design do construtor nos ajuda a construir um objeto de uma forma mais simples e legível. O padrão de design do construtor segue duas regras simples mencionadas abaixo. O padrão de design do construtor nos ajuda a construir objetos de uma forma mais simples e legível. O padrão de design do construtor segue duas regras simples, descritas abaixo.

  1. Separe a representação da classe original e seus métodos de construção. Separe a representação da classe original e seu construtor.

  2. retorna a instância da classe na etapa final Retorne uma instância da classe na etapa final

O melhor exemplo de padrão de design de construtor é SwiftUI, sim, você leu certo. SwiftUI usa padrão de design de construtor para a maioria de suas classes, por exemplo. Texto, Imagem O melhor exemplo de padrão de design de construtor é SwiftUI, sim, você leu certo. A maioria das classes no SwiftUI usa o padrão de design do construtor, como texto, imagens, etc.

Problema: Pergunta:

Pense na classe, digamos Person, com dez ou mais propriedades, imaginando seu design de construtor quando você precisar criar uma instância da classe Person. Seu construtor receberá dez ou mais argumentos, será difícil gerenciar esses muitos argumentos como uma única função ou construtor e, eventualmente, você perderá a legibilidade do código. confira o exemplo abaixo. Pense nesta classe, digamos Person tendo dez ou mais propriedades, quando você precisar criar uma instância da classe Person, imagine seu design de construtor. Seu construtor requer 10 ou mais parâmetros, que são difíceis de gerenciar como uma função ou construtor e, eventualmente, você perde a legibilidade do seu código. Confira o exemplo abaixo.


WithoutDesignPatternExample1.swift:

class Person {
  //personal details
  var name: String = ""
  var gender: String = ""
  var birthDate: String = ""
  var birthPlace: String = ""
  var height: String = ""
  var weight: String = ""
  
  //contact details
  var phone: String = ""
  var email: String = ""
  
  //address details
  var streeAddress: String = ""
  var zipCode: String = ""
  var city: String = ""
  
  //work details
  var companyName: String = ""
  var designation: String = ""
  var annualIncome: String = ""
  
  //constructor
  init(name: String,
       gender: String,
       birthDate: String,
       birthPlace: String,
       height: String,
       weight: String,
       phone: String,
       email: String,
       streeAddress: String,
       zipCode: String,
       city: String,
       companyName: String,
       designation: String,
       annualIncome: String) {
    self.name = name
    self.gender = gender
    self.birthDate = birthDate
    self.birthPlace = birthPlace
    self.height = height
    self.weight = weight
    self.phone = phone
    self.email = email
    self.streeAddress = streeAddress
    self.zipCode = zipCode
    self.height = height
    self.city = city
    self.companyName = companyName
    self.designation = designation
    self.annualIncome = annualIncome
  }
}

//This is function in Xcode-Playground which executes our test code
func main() {
  let hitendra = Person(name: "Hitendra Solanki",
                        gender: "Male",
                        birthDate: "2nd Oct 1991",
                        birthPlace: "Gujarat, India",
                        height: "5.9 ft",
                        weight: "85kg",
                        phone: "+91 90333-71772",
                        email: "hitendra.developer@gmail.com",
                        streeAddress: "52nd Godrej Street",
                        zipCode: "380015",
                        city: "Ahmedabad",
                        companyName: "Fortune 500",
                        designation: "Software architect",
                        annualIncome: "45,000 USD")
  
  //use of Person object
  print("\(hitendra.name) works in \(hitendra.companyName) compay as a \(hitendra.designation).")
}

//call main to execute our test code in Xcode-Playground
main()

/* Console output:
Hitendra Solanki works in Fortune 500 compay as a Software architect.
*/

Tente executar o exemplo acima no playground, ele será executado com sucesso e fornecerá o resultado esperado. Logicamente está correto. Tente executar o exemplo acima no playground, ele será executado com êxito e fornecerá o resultado esperado. Logicamente correto.

Podemos melhorar o exemplo acima, superando os pontos abaixo. Podemos melhorar o exemplo acima superando os seguintes pontos.

  1. Temos que passar os valores na ordem mencionada, não podemos reordenar a sequência dos parâmetros para melhorar a legibilidade. Devemos passar os valores na ordem acima, a sequência de parâmetros não pode ser reordenada para melhorar a legibilidade.

  2. Temos que passar todos os valores, mesmo que não conheçamos alguns valores no momento da criação do objeto. Devemos passar todos os valores, mesmo que não conheçamos alguns valores ao criar o objeto.

Por exemplo Suponha que você precise criar um objeto da classe Person, mas a pessoa ainda está procurando emprego. Quando essa pessoa ingressar em alguma empresa só então teremos os detalhes do trabalho. Suponha que você precise criar um objeto da classe Pessoa, mas o objeto ainda está procurando trabalho. Quando essa pessoa ingressar em alguma empresa, só nós teremos os detalhes da vaga.

Solução:

Solução:

  1. Crie grupos lógicos de propriedades relacionadas. Crie grupos lógicos de propriedades relacionadas.

  2. Crie classes construtoras separadas para diferentes grupos de propriedades [ajuda na normalização de propriedades, isso é opcional. Criar classes geradoras separadas para diferentes grupos de atributos [ajuda na normalização de atributos, isso é opcional.

  3. Recupere uma instância na etapa final. Uma instância é recuperada na etapa final.

Vamos simplificar isso com um exemplo, Vamos simplificar com um exemplo,

Já temos uma classe chamada Person no exemplo WithoutDesignPatternExample1.swift, na qual temos 14 propriedades. Se verificarmos atentamente todas as 14 propriedades, as propriedades terão 4 grupos lógicos. Por exemplo, já temos uma classe chamada Person sem designpatternexample1. Swift, temos 14 propriedades. Se examinarmos cuidadosamente todas as 14 propriedades, existem 4 grupos lógicos dessas propriedades.

  1. Propriedades de dados pessoais Atributos de informações pessoais

  2. Propriedades de detalhes de contato Propriedades de informações de contato

  3. Propriedades de detalhes do endereço Propriedades de detalhes de endereço

  4. Propriedades de detalhes da empresa Detalhes da empresa propriedades

Os padrões de design facetado e fluente juntos nos ajudam a superar os dois problemas mencionados acima. Os padrões de design Facetado e Fluente juntos nos ajudam a superar os dois problemas mencionados acima.


BuilderDesignPattern[Faceted+Fluent]Example1.swift:

//This is function in playground which executes our test code
func main() {
  
  var hitendra = Person() //person with empty details
  let personBuilder = PersonBuilder(person: hitendra)
  
  hitendra = personBuilder
    .personalInfo
      .nameIs("Hitendra Solanki")
      .genderIs("Male")
      .bornOn("2nd Oct 1991")
      .bornAt("Gujarat, India")
      .havingHeight("5.9 ft")
      .havingWeight("85 kg")
    .contacts
      .hasPhone("+91 90333-71772")
      .hasEmail("hitendra.developer@gmail.com")
    .lives
      .at("52nd Godrej Street")
      .inCity("Ahmedabad")
      .withZipCode("380015")
    .build()
  
  //use of Person object
  print("\(hitendra.name) has contact number \(hitendra.phone) and email \(hitendra.email)")
  
  //later on when we have company details ready for the person
  hitendra = personBuilder
    .works
      .asA("Software architect")
      .inCompany("Fortune 500")
      .hasAnnualEarning("45,000 USD")
    .build()
  
  //use of Person object with update info
  print("\(hitendra.name) works in \(hitendra.companyName) compay as a \(hitendra.designation).")
}

//call main to execute our test code
main()

//Person class which only contains the details
class Person {
  //personal details
  var name: String = ""
  var gender: String = ""
  var birthDate: String = ""
  var birthPlace: String = ""
  var height: String = ""
  var weight: String = ""
  
  //contact details
  var phone: String = ""
  var email: String = ""
  
  //address details
  var streeAddress: String = ""
  var zipCode: String = ""
  var city: String = ""
  
  //work details
  var companyName: String = ""
  var designation: String = ""
  var annualIncome: String = ""
  
  //empty constructor
  init() { }
}

//PersonBuilder class helps to construct the person class instance
class PersonBuilder {
  var person: Person
  init(person: Person){
    self.person = person
  }
  
  //personal details builder switching
  var personalInfo: PersonPersonalDetailsBuilder {
    return PersonPersonalDetailsBuilder(person: self.person)
  }
  
  //contact details builder switching
  var contacts: PersonContactDetailsBuilder {
    return PersonContactDetailsBuilder(person: self.person)
  }
  
  //address details builder switching
  var lives: PersonAddressDetailsBuilder {
    return PersonAddressDetailsBuilder(person: self.person)
  }
  
  //work details builder switching
  var works: PersonCompanyDetailsBuilder {
    return PersonCompanyDetailsBuilder(person: self.person)
  }
  
  func build() -> Person {
    return self.person
  }
}

//PersonPersonalDetailsBuilder: update personal details
class PersonPersonalDetailsBuilder: PersonBuilder {
  func nameIs(_ name: String) -> Self {
    self.person.name = name
    return self
  }
  func genderIs(_ gender: String) -> Self {
    self.person.gender = gender
    return self
  }
  func bornOn(_ birthDate: String) -> Self {
    self.person.birthDate = birthDate
    return self
  }
  func bornAt(_ birthPlace: String) -> Self {
    self.person.birthPlace = birthPlace
    return self
  }
  func havingHeight(_ height: String) -> Self {
    self.person.height = height
    return self
  }
  func havingWeight(_ weight: String) -> Self {
    self.person.weight = weight
    return self
  }
}

//PersonContactDetailsBuilder: update contact details
class PersonContactDetailsBuilder: PersonBuilder {
  func hasPhone(_ phone: String) -> Self {
    self.person.phone = phone
    return self
  }
  func hasEmail(_ email: String) -> Self {
    self.person.email = email
    return self
  }
}

//PersonAddressDetailsBuilder: update address details
class PersonAddressDetailsBuilder: PersonBuilder {
  func at(_ streeAddress: String) -> Self {
    self.person.streeAddress = streeAddress
    return self
  }
  func withZipCode(_ zipCode: String) -> Self {
    self.person.zipCode = zipCode
    return self
  }
  func inCity(_ city: String) -> Self {
    self.person.city = city
    return self
  }
}

//PersonCompanyDetailsBuilder: update company details
class PersonCompanyDetailsBuilder: PersonBuilder {
  func inCompany(_ companyName: String) -> Self {
    self.person.companyName = companyName
    return self
  }
  func asA(_ designation: String) -> Self {
    self.person.designation = designation
    return self
  }
  func hasAnnualEarning(_ annualIncome: String) -> Self {
    self.person.annualIncome = annualIncome
    return self
  }
}

/* Console output:
 
 Hitendra Solanki has contact number +91 90333-71772 and email hitendra.developer@gmail.com
 Hitendra Solanki works in Fortune 500 compay as a Software architect.
 
 */

No exemplo acima, separamos as responsabilidades da classe Person em diferentes classes. A classe Person agora contém apenas as propriedades de dados, enquanto criamos várias classes construtoras com responsabilidades de construir/atualizar o grupo relativo de propriedades. No exemplo acima, dividimos as responsabilidades da classe Person em diferentes classes. A classe Person agora contém apenas atributos de dados e criamos várias classes construtoras que são responsáveis ​​por construir/atualizar grupos de atributos relacionados.Temos uma classe construtora base PersonBuilder e mais quatro classes construtoras derivadas chamadas PersonPersonalDetailsBuilder, PersonContactDetailsBuilder, PersonAddressDetailsBuilder e PersonCompanyDetailsBuilder. Temos uma classe de construtor básica PersonBuilder e quatro classes de construtor derivadas, nomeadamente PersonPersonalDetailsBuilder, PersonContactDetailsBuilder, PersonAddressDetailsBuilder e PersonCompanyDetailsBuilder.

A classe base PersonBuilder nos ajuda a alternar entre vários construtores a qualquer momento, enquanto outros quatro construtores derivados de PersonBuilder têm responsabilidades de atualizar propriedades relativas. A classe base PersonBuilder nos ajuda a alternar entre vários construtores a qualquer momento, enquanto os outros quatro construtores derivados de PersonBuilder são responsáveis ​​por atualizar as propriedades relacionadas.

No exemplo acima, podemos ver claramente que a construção de um objeto Person é mais legível em comparação com nosso primeiro exemplo WithoutDesignPatternExample1.swift e também podemos atualizar o grupo de propriedades ou qualquer propriedade única a qualquer momento de uma maneira mais legível. No exemplo acima, podemos ver claramente que a estrutura do objeto Person é muito mais legível em comparação com o nosso primeiro exemplo.

No exemplo acima, observe que estamos retornando a própria instância do construtor após chamar cada método de atualização de propriedade. O que nos ajuda a escrever o encadeamento de vários métodos do mesmo construtor, em vez de escrever várias linhas separadamente. Este conceito é conhecido como padrão Fluente. No exemplo acima, observe que após chamar cada método de atualização de propriedade, retornamos a própria instância do gerador. Isso nos ajuda a escrever o encadeamento de vários métodos do mesmo gerador em vez de escrever várias linhas separadas. Este conceito é chamado de modo de coerência.

Benefícios:

Benefícios:

  1. Inicialize facilmente um objeto de uma classe com muitas propriedades de uma maneira mais legível. Inicializa facilmente um objeto de uma classe com muitas propriedades, para melhor legibilidade.

  2. Segue o princípio da responsabilidade única. Siga o princípio da responsabilidade única.

  3. Inicialize o objeto ou atualize as propriedades em qualquer ordem conforme sua conveniência. Inicialize objetos ou atualize propriedades em qualquer ordem conforme sua conveniência.

Bônus:

Bônus:

Para tornar o padrão do construtor consistente em todo o projeto, você pode criar o protocolo conforme abaixo. Para tornar o padrão do gerador consistente em todo o seu projeto, você pode criar um protocolo como o seguinte.

Texto original: https://medium.com/flawless-app-stories/design-patterns-by-tutorials-the-power-of-oop-2e871b551cbe