samedi 18 novembre 2017

How to properly apply a Factory Method Design Pattern in Swift 4?

I am NOT looking for a simple factory method pattern.

Could you help me out in refactoring the code below to properly use the factory method design pattern in Swift 4?

I'm afraid I don't get it well enough how to apply it in Swift.

There are a couple problems I have in the example below:

  • the ItalianPizzeria shouldn't be able to return AmericanCheesePizza
  • The AmericanPizzeria shouldn't be able to return ItailanCheesePizza
  • The makePizza() method should be probably private. It should not be possible to write italianPizzeria.makePizza(pizzaType:)

If I have badly applied the factory method, how to apply it properly? I can't find any websites, books or tutorials that would help me solve this exact problem with applying that design pattern to this case.

You should be able to copy/paste the code below to a playground, if it makes your life easier.

enum PizzaType {
    case italianCheesePizza
    case americanCheesePizza
}

protocol Pizza {
    var name: String {get set}
    var dough: String {get set}
    var sauce: String {get set}
    var toppings: Array<String> {get set}

    func prepare()
    func bake()
    func slice()
    func pack()
}

extension Pizza {
    func prepare() {
        print("Preparing: \(name)")
        print("Making dough...")
        print("Adding sauce...")
        print("Toppings: ")
        for topping in toppings {
            print(topping)
        }
    }

    func bake() {
    print("Baking: 25 minutes in 350 degrees Celsjus")
    }

    func slice() {
        print("Slicing pizza into 8 pieces")
    }

    func pack() {
        "Packing pizza in an orinal box of our Pizza Store Chain."
    }
}

class ItalianCheesePizza: Pizza {
    var name: String = "Italian pizza with Marinara sauce"
    var dough: String = "Thin crispy dough"
    var sauce: String = "Marinara Sauce"
    var toppings: Array<String> = ["Reggiano grated cheese"]
}

class AmericanCheesePizza: Pizza {
    var name: String = "American Cheese Pizza"
    var dough: String = "Extra thick, crispy dough"
    var sauce: String = "Tomato sauce"
    var toppings: Array<String> = ["Thick grated Mozarella cheese"]

    func slice() {
        print("Slicing pizza into square pieces")
    }
}

protocol Pizzeria {
    func orderPizza(pizzaType: PizzaType) -> Pizza
    func makePizza(pizzaType: PizzaType) -> Pizza // This is the factory method
}

extension Pizzeria {
    func orderPizza(pizzaType: PizzaType) -> Pizza {
        var pizza: Pizza
        pizza = makePizza(pizzaType: pizzaType)

        pizza.prepare()
        pizza.bake()
        pizza.slice()
        pizza.pack()

        return pizza
    }
}

class ItalianPizzeria: Pizzeria {
    func makePizza(pizzaType: PizzaType) -> Pizza {
        switch pizzaType { // I should be able to return only Italian pizza types
        case .italianCheesePizza:
            return ItalianCheesePizza()
        case .americanCheesePizza:
            return AmericanCheesePizza()
        }
    }
}

class AmericanPizzeria: Pizzeria {
    func makePizza(pizzaType: PizzaType) -> Pizza {
        switch pizzaType { // I should be able to return only American pizza types
        case .italianCheesePizza:
            return ItalianCheesePizza()
        case .americanCheesePizza:
            return AmericanCheesePizza()
        }
    }
}

let italianPizzeria = ItalianPizzeria()
let americanPizzeria = AmericanPizzeria()

var pizza: Pizza

pizza = italianPizzeria.orderPizza(pizzaType: .italianCheesePizza)
pizza = americanPizzeria.orderPizza(pizzaType: .americanCheesePizza) // I think the method makePizza(pizzaType:) should be hidden here.

Aucun commentaire:

Enregistrer un commentaire