抽象工厂模式 Abstract factory

维基百科:

抽象工厂模式提供了一种封装一组具有共同主题但没有指定其具体类的单个工厂的方法

问题描述

从之前讲到的简单工厂扩展出新的问题. 可以从木门店买木门, 从铁门店买铁门, 或者从别的店买玻璃门. 另外, 在之后的安程过程中, 需要有木匠来 安装木门, 焊工安装铁门等等. 可以看到, 门与安装工之间存在着依赖关系, 木门需要木匠, 铁门需要焊工, 而玻璃门需要别的安装工.

代码示例

#![allow(dead_code)]

pub trait Door {
    fn get_description(&self);
}

struct WoodenDoor {}

impl Door for WoodenDoor {
    fn get_description(&self) {
        println!("I am a wooden door");
    }
}

struct IronDoor {}

impl Door for IronDoor {
    fn get_description(&self) {
        println!("I am an iron door");
    }
}

pub trait DoorFittingExpert {
    fn get_description(&self);
}

struct Carpenter {}

impl DoorFittingExpert for Carpenter {
    fn get_description(&self) {
        println!("I can only fit wooden doors");
    }
}

struct Welder {}

impl DoorFittingExpert for Welder {
    fn get_description(&self) {
        println!("I can only fit iron doors");
    }
}

pub trait DoorFactory {
    fn make_door(&self) -> Box<dyn Door>;

    fn make_fitting_expert(&self) -> Box<dyn DoorFittingExpert>;
}

pub struct WoodenDoorFactory {}

impl Default for WoodenDoorFactory {
    fn default() -> Self {
        Self::new()
    }
}

impl WoodenDoorFactory {
    #[must_use]
    pub const fn new() -> Self {
        Self {}
    }
}

impl DoorFactory for WoodenDoorFactory {
    fn make_door(&self) -> Box<dyn Door> {
        Box::new(WoodenDoor {})
    }

    fn make_fitting_expert(&self) -> Box<dyn DoorFittingExpert> {
        Box::new(Carpenter {})
    }
}

pub struct IronDoorFactory {}

impl Default for IronDoorFactory {
    fn default() -> Self {
        Self::new()
    }
}

impl IronDoorFactory {
    #[must_use]
    pub const fn new() -> Self {
        Self {}
    }
}

impl DoorFactory for IronDoorFactory {
    fn make_door(&self) -> Box<dyn Door> {
        Box::new(WoodenDoor {})
    }

    fn make_fitting_expert(&self) -> Box<dyn DoorFittingExpert> {
        Box::new(Carpenter {})
    }
}

fn main() {
    println!("test_dynamic_dispatch()");

    {
        let wooden_factory = WoodenDoorFactory::new();
        let door = wooden_factory.make_door();
        door.get_description();
        let expert = wooden_factory.make_fitting_expert();
        expert.get_description();
    }

    {
        let iron_factory = IronDoorFactory::new();
        let door = iron_factory.make_door();
        door.get_description();
        let expert = iron_factory.make_fitting_expert();
        expert.get_description();
    }
}