Menu
Coddy logo textTech

Patron Fabrique

Fait partie de la section Programmation orientée objet du Journey Swift de Coddy. Leçon 43 sur 57.

Le modèle fabrique centralise la création des objets. Les appelants demandent ce dont ils ont besoin, souvent par nom ou par type, et reçoivent un objet prêt à l’emploi, sans savoir quel type concret a été construit :

protocol Shape { func area() -> Double }
struct Square: Shape { let side: Double; func area() -> Double { side * side } }
struct Circle: Shape { let r: Double; func area() -> Double { 3 * r * r } }

enum ShapeFactory {
    static func make(_ kind: String, size: Double) -> (any Shape)? {
        switch kind {
        case "square": return Square(side: size)
        case "circle": return Circle(r: size)
        default: return nil
        }
    }
}

print(ShapeFactory.make("square", size: 3)!.area())
print(ShapeFactory.make("hexagon", size: 3) == nil)

Sortie :

9.0
true

L’appelant ne dépend que du protocole. Ajouter une nouvelle forme signifie modifier la fabrique, et non chaque endroit qui crée des formes :

protocol Notifier { func send(_ m: String) -> String }
struct Email: Notifier { func send(_ m: String) -> String { "email: \(m)" } }
struct SMS: Notifier { func send(_ m: String) -> String { "sms: \(m)" } }

func makeNotifier(for user: String) -> any Notifier {
    user.hasSuffix("@mail.com") ? Email() : SMS()
}

print(makeNotifier(for: "ada@mail.com").send("hi"))
print(makeNotifier(for: "555-0100").send("hi"))

Sortie :

email: hi
sms: hi

Les méthodes d’usine statiques sur le type lui-même constituent une forme plus légère du modèle. Elles donnent des noms aux façons courantes de construire une valeur :

struct Color {
    let r: Int, g: Int, b: Int
    static func gray(_ v: Int) -> Color { Color(r: v, g: v, b: v) }
    static let white = Color(r: 255, g: 255, b: 255)
}

print(Color.gray(100).g)
print(Color.white.b)

Sortie :

100
255

Un enum sans cas, tel que ShapeFactory, est un moyen courant de regrouper des fonctions de fabrique : il ne peut pas être instancié et fonctionne donc uniquement comme espace de noms.

enum ShapeFactory {        // aucun cas : ne peut pas être créé
    static func make(_ kind: String, size: Double) -> (any Shape)? { ... }
}
challenge icon

Défi

Facile

Écrivez une fabrique pour les plans tarifaires. Le protocole Plan possède name et price(forUsers:) -> Int. Implémentez Free (0, et uniquement jusqu’à 3 utilisateurs : au-delà, le prix est de -1, ce qui signifie que ce n’est pas autorisé), Team (10 par utilisateur) et Enterprise (500 au forfait, plus 5 par utilisateur au-delà de 100). Complétez PlanFactory.make(_:), qui renvoie le plan pour free, team ou enterprise, et nil dans les autres cas.

Le code fourni lit des lignes plan,users et affiche team for 12 users: 120, free does not allow 5 users ou unknown plan: gold.

Votre code doit se trouver dans Plan.swift, Free.swift, Team.swift, Enterprise.swift et PlanFactory.swift. main.swift contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

// Code d'entrée/sortie fourni : le garder tel quel
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
    let p = line.split(separator: ",").map(String.init)
    let users = Int(p[1])!
    guard let plan = PlanFactory.make(p[0]) else {
        print("unknown plan: \(p[0])")
        continue
    }
    let price = plan.price(forUsers: users)
    print(price < 0 ? "\(plan.name) does not allow \(users) users" : "\(plan.name) for \(users) users: \(price)")
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Playground Swift