Smart Machines and Factories Blog Uncategorized Fábrica [Design Patterns with Swift (Part 1)]

Fábrica [Design Patterns with Swift (Part 1)]

Fábrica [Design Patterns with Swift (Part 1)] post thumbnail image

O padrão de projeto Factory é um padrão de projeto de criação que é dividido em dois padrões: o método Factory e o Abstract Factory.

A idéia por trás do padrão de projeto Factory é criar um novo objeto. Mas por que devemos usar o padrão de projeto Factory?

  • Criação de objetos mais fácil:Por vezes, a criação de objectos pode ser demasiado complicada. Mesmo que tenha menos parâmetros ou menos informações sobre a classe, pode criar o objeto sem ter de lidar com eles.
  • Menos dependente: O padrão de desenho Factory permite a comunicação através da abstração de objectos, impedindo a classe de se ligar diretamente a um objeto. Isso diminui as dependências da classe e a torna mais flexível. Além disso, o código torna-se mais testável.
  • O inicializador não é descritivo:Em vez de usar o padrão de projeto Factory, podemos usar init para a criação de objetos. Além disso, podemos ter vários métodos init para diferentes propósitos. Embora os argumentos do método init sejam diferentes, ele ainda é chamado de init, tornando difícil entender como os métodos init diferem uns dos outros. Quando o padrão de projeto Factory é aplicado, o método associado pode ser nomeado de acordo com sua função, levando a uma estrutura de inicialização mais detalhada.

Vamos supor que existe uma classe com o nome “Arroz”. Um objeto de Arroz (para preparar uma mesa de arroz, neste caso) pode ser criado de duas formas diferentes: cozinhando as matérias-primas (arroz, óleo, água e sal) ou utilizando um pacote pronto a comer.

typealias Gram = Double

class Rice {
let rice: Gram
let oil: Gram
let water: Gram
let salt: Gram

init(rice: Gram, oil: Gram, water: Gram, salt: Gram) {
self.rice = rice
self.oil = oil
self.water = water
self.salt = salt
}

init(readyToEatPacket: Gram) {
rice = readyToEatPacket * 0.6
oil = readyToEatPacket * 0.1
water = readyToEatPacket * 0.38
salt = readyToEatPacket * 0.02
}
}

Método de fabrico

O método Factory é um tipo de método estático que cria um objeto.

class Rice {
...

private init(rice: Gram, oil: Gram, water: Gram, salt: Gram) {
...
}

private init(readyToEatPacket: Gram) {
...
}

static func createFromRawRice(rice: Gram, oil: Gram, water: Gram, salt: Gram) -> Rice {
return Rice(rice: rice, oil: oil, water: water, salt: salt)
}

static func createFromPackagedRice(readyToEatPacket: Gram) -> Rice {
return Rice(readyToEatPacket: readyToEatPacket)
}
}

let riceFromRawRice = Rice.createFromRawRice(rice: 200, oil: 40, water: 400, salt: 10)
print(riceFromRawRice.rice) // Prints "200"

let readyToEatRice = Rice.createFromPackagedRice(readyToEatPacket: 100)
print(readyToEatRice.rice) // Prints "60"

Temos dois métodos Factory diferentes: createFromRawRice e createFromPackagedRice. Estes métodos estão localizados dentro da classe. Utilizam os parâmetros necessários e, em seguida, devolvem o objeto Arroz. A principal vantagem do design Factory em relação aos inicializadores é o facto de ter um nome mais descritivo. Neste caso, é fácil perceber qual o material a utilizar para fazer o Arroz.

Uma das características notáveis desta implementação é que os métodos do inicializador são agora privados. Como resultado, os únicos métodos responsáveis pela criação de um objeto são os métodos Factory.

Fábrica

No padrão Factory, à exceção do método Factory, os métodos que criam um objeto são subcontratados a uma classe específica.

class RiceFactory {
static func createFromRawRice(rice: Gram, oil: Gram, water: Gram, salt: Gram) -> Rice {
return Rice(rice: rice, oil: oil, water: water, salt: salt)
}

static func createFromPackagedRice(readyToEatPacket: Gram) -> Rice {
return Rice(readyToEatPacket: readyToEatPacket)
}
}

let riceFromRawRice = RiceFactory.createFromPackagedRice(readyToEatPacket: 200)

// if createFromRawRice and createFromPackagedRice are not static;

let riceFactory = RiceFactory()
let riceFromRawRice = riceFactory.createFromPackagedRice(readyToEatPacket: 200)

A classe RiceFactory possui métodos Factory. É opcional que esses métodos sejam estáticos. Por outro lado, os métodos init de Rice não são mais privados. Este é um tópico importante a ser considerado desta forma.

Fábrica Interna

Inner Factory significa basicamente que a classe fábrica está dentro da classe relacionada.

class Rice {
...

private init(rice: Gram, oil: Gram, water: Gram, salt: Gram) {
...
}

private init(readyToEatPacket: Gram) {
...
}

class RiceFactory {
static func createFromRawRice(rice: Gram, oil: Gram, water: Gram, salt: Gram) -> Rice {
return Rice(rice: rice, oil: oil, water: water, salt: salt)
}

static func createFromPackagedRice(readyToEatPacket: Gram) -> Rice {
return Rice(readyToEatPacket: readyToEatPacket)
}
}
}

let rice = Rice.RiceFactory.createFromRawRice(rice: 100, oil: 10, water: 200, salt: 5)

Como pode ver no snippet acima, a RiceFactory está localizada dentro da Rice. Os inicializadores tornaram-se privados. Novamente, os métodos estáticos podem ser substituídos por métodos não-estáticos e, consequentemente, o uso pode ser o seguinte.

let rice = Rice.RiceFactory().createFromRawRice(rice: 100, oil: 10, water: 200, salt: 5)

Se este método for utilizado, são criados vários objectos RiceFactory. Além disso, se certas informações forem mantidas na RiceFactory, elas serão perdidas a cada criação da RiceFactory. Para resolver este problema, a classe RiceFactory pode ser transformada em Singleton e, em seguida, é utilizada uma instância estática para aceder à fábrica. A implementação está abaixo.

class Rice {
...

private init(rice: Gram, oil: Gram, water: Gram, salt: Gram) {
...
}

private init(readyToEatPacket: Gram) {
...
}

static let factory = RiceFactory.instance

class RiceFactory {
private init() {}
static let instance = RiceFactory()

func createFromRawRice(rice: Gram, oil: Gram, water: Gram, salt: Gram) -> Rice {
return Rice(rice: rice, oil: oil, water: water, salt: salt)
}

func createFromPackagedRice(readyToEatPacket: Gram) -> Rice {
return Rice(readyToEatPacket: readyToEatPacket)
}
}
}

let rice = Rice.factory.createFromRawRice(rice: 100, oil: 10, water: 200, salt: 5)

Fábrica Abstrata

O Abstract Factory define uma interface para a criação de famílias de produtos sem especificar as suas classes concretas. A criação é implementada por classes concretas. Cada classe concreta é responsável pela criação de um tipo. O esquema do Abstract Factory é o seguinte.

protocol FourWheelerVehicle {
func drive()
}

class Car: FourWheelerVehicle {
func drive() {
print("Car is driven")
}
}

class Truck: FourWheelerVehicle {
func drive() {
print("Truck is driven")
}
}

protocol TwoWheelerVehicle {
func ride()
}

class Motorcycle: TwoWheelerVehicle {
func ride() {
print("Motorcycle is ridden")
}
}

class Scooter: TwoWheelerVehicle {
func ride() {
print("Scooter is ridden")
}
}

protocol VehicleFactory {
func manufactureFourWheelerVehicle() -> FourWheelerVehicle
func manufactureTwoWheelerVehicle() -> TwoWheelerVehicle
}

class XBrandFactory: VehicleFactory {
func manufactureFourWheelerVehicle() -> FourWheelerVehicle {
print("Car has been manufactured")
return Car()
}

func manufactureTwoWheelerVehicle() -> TwoWheelerVehicle {
print("Motorcycle has been manufactured")
return Motorcycle()
}
}

class YBrandFactory: VehicleFactory {
func manufactureFourWheelerVehicle() -> FourWheelerVehicle {
print("Truck has been manufactured")
return Truck()
}

func manufactureTwoWheelerVehicle() -> TwoWheelerVehicle {
print("Scooter has been manufactured")
return Scooter()
}
}

class ABCMotorVehicles {
private var brand: String
private var vehicleFactory: VehicleFactory?

init(brand: String) {
self.brand = brand
}

private func initVehicleFactory() {
if brand == "X" {
vehicleFactory = XBrandFactory()
} else {
vehicleFactory = YBrandFactory()
}
}

func manufactureFourWheelerVehicle() -> FourWheelerVehicle {
initVehicleFactory()
return vehicleFactory!.manufactureFourWheelerVehicle()
}

func manufactureTwoWheelerVehicle() -> TwoWheelerVehicle {
initVehicleFactory()
return vehicleFactory!.manufactureTwoWheelerVehicle()
}
}

var company = ABCMotorVehicles(brand: "X")
let productA1 = company.manufactureFourWheelerVehicle() // Prints "Car has been manufactured"
productA1.drive() // Prints "Car is driven"
let productB1 = company.manufactureTwoWheelerVehicle() // Prints "Motorcycle has been manufactured"
productB1.ride() // Prints "Motorcycle is ridden"

company = ABCMotorVehicles(brand: "Y")
let productA2 = company.manufactureFourWheelerVehicle() // Prints "Truck has been manufactured"
productA2.drive() // Prints "Truck is driven"
let productB2 = company.manufactureTwoWheelerVehicle() // Prints "Scooter has been manufactured"
productB2.ride() // Prints "Scooter is ridden"

Temos um longo trecho de código. Vamos torná-lo significativo.

FourWheelerVehicle -> AbstractProductA

Carro -> ProdutoA1

Camião -> ProdutoA2

Veículo de duas rodas -> AbstractProductB

Motociclo -> ProdutoB1

Scooter -> ProdutoB2

VehicleFactory -> AbstractFactory

XBrandVehicleFactory -> ConcreteFactory1

YBrandVehicleFactory -> ConcreteFactory2

Cliente -> ABCMotorVehicles

Como pode ver na correspondência, a fábrica abstrata é VehicleFactory. VehicleFactory definiu uma interface, e depois XBrandVehicleFactory e YBrandVehicleFactory conformaram-na. O cliente ABCMotorVehicles recebe apenas o parâmetro da marca, depois inicializa a VehicleFactory de acordo com a marca. Uma vez que o cliente conhece a marca, pode criar produtos (Carro, Camião, etc.) em conformidade com os protocolos AbstractProduct (FourWheelerVehicle, etc.).

Related Post

Garantindo a qualidade e a segurança: O compromisso da Happy Forgings Ltd. com os padrões de conformidadeGarantindo a qualidade e a segurança: O compromisso da Happy Forgings Ltd. com os padrões de conformidade

Numa era em que a ética empresarial e a responsabilidade corporativa nunca foram tão escrutinadas, as empresas que dão prioridade às normas de conformidade distinguem-se como faróis de integridade e