Design Pattern in Rust: Abstract Factory

Design Pattern in Rust: Abstract Factory

Ly Nhan

2 years 5 min read

Cung cấp một interface để khởi tạo các objects có liên quan đến nhau mà không cần quan tâm đến implementation của các object này.

Ở phía client chỉ làm việc với interface, việc các class implement interface này như thế nào client không cần quan tâm.

Ví dụ:

Khi bạn ở trong một giao diện có các windows và scrollbar, user có thể switch và chọn các theme khác nhau, chức năng của các class trên có thể không đổi nhưng việc thể hiện UI ra ngoài sẽ khác theo từng theme.

Nếu apply abstrat factory vào trường hợp này, phía client sẽ chỉ làm việc với WidgetFactory, và các theme khi plug vào phải implement WidgetFactory này thì có thể apply được theme mới mà không cần thay đổi quá nhiều code ở client, và client cũng không cần biết theme mới được implement như thế nào.

Bạn có thể xem diagram ở hình dưới:

nextlint

Ứng dụng:

  • Hệ thống không bị phụ thuộc vào cách mà sản phẩm được khởi tạo

  • Hệ thống được tao thành từ một hoặc nhiều sản phẩm liên quan đến nhau.

  • Có rất nhiều sản phẩm implement từ một interface, và ở phía client chỉ làm việc với interface này.

Ứng dụng của nó khá là trừu tượng, mình sẽ đưa ra một ví dụ cụ thể hén:

Bạn đang thiết kế 1 cái khung xe có rất nhiều thành phần, bánh xe, gương chiếu hậu, cửa, đèn bla bla.... Và các thành phần trên có rất nhiều style khác nhau, ví dụ gương thì có cầu hồi lõm, bể chẳng hạn :)). Đèn thì đèn xanh đèn vàng.

Lúc này khung xe chỉ cần expose ra 1 interface để quy định việc khởi tạo các thành phần để được plug vào, còn việc các thành phần đó khởi tạo như thế nào tui không cần biết, chỉ cần bạn tuân theo đúng interface tui đưa ra là có thể plug vào được.

Implementation

Ở đây mình sẽ implement theo ví dụ trong sách luôn, implement một WidgetFactory có thể khởi tạo được các object Window, Scrollbar.

#[derive(Debug, Clone, Default)]
pub struct Window {
    pub background: String,
    pub text: String,
    pub widget_name: String,
}
#[derive(Debug, Clone, Default)]
pub struct ScrollBar {
    pub width: i64,
    pub height: i64,
    pub widget_name: String,
}
#[derive(Debug, Clone)]
pub struct ThemeInfo {
    pub name: String,
}

#[derive(Debug, Clone, Copy)]
pub enum Themes {
    PMWindow,
    Motif,
}

Define interface:

pub trait WidgetFactory {
        fn create_window(&self) -> Window;
        fn create_scroll_bar(&self) -> ScrollBar;
        fn get_theme_info(&self) -> ThemeInfo;
    }

Giờ mình sẽ có 2 loại widget là PMWidget và MotifWidget thì sẽ implement trait ở trên như sau:

PMWindowWidget

pub struct PMWindowWidget {}
    impl WidgetFactory for PMWindowWidget {
        fn create_window(&self) -> Window {
            Window {
                background: "white".into(),
                text: "green".into(),
                widget_name: "PMWindow".to_string(),
            }
        }

        fn create_scroll_bar(&self) -> ScrollBar {
            ScrollBar {
                width: 300,
                height: 300,
                widget_name: "ScrollBar".to_string(),
            }
        }

        fn get_theme_info(&self) -> ThemeInfo {
            ThemeInfo {
                name: "PMWindow Widget".into(),
            }
        }

MotifWidget

pub struct MotifWidget {}
    impl WidgetFactory for MotifWidget {
        fn create_window(&self) -> Window {
            Window {
                background: "green".into(),
                text: "white".into(),
                widget_name: "MotifScollbar".to_string(),
            }
        }

        fn create_scroll_bar(&self) -> ScrollBar {
            ScrollBar {
                width: 200,
                height: 200,
                widget_name: "MotifScollbar".to_string(),
            }
        }
        fn get_theme_info(&self) -> ThemeInfo {
            ThemeInfo {
                name: "Motif Widget".into(),
            }
        }
    }

Implement ở phía client:

// https://doc.rust-lang.org/rust-by-example/trait/dyn.htm
    pub fn get_widget_factory(theme: Themes) -> Box<dyn WidgetFactory> {
        match theme {
            Themes::PMWindow => Box::new(PMWindowWidget {}),
            Themes::Motif => Box::new(MotifWidget {}),
        }
    }

Fullcode implement ở đây nha:

https://github.com/lynhan318/rust-design-pattern/blob/main/crates/creational/src/factory.rs

Cảm ơn các bạn đã xem bài viết, hẹn gặp lại ở các pattern tiếp theo hén 😊

High level experience in web design and development knowledge, producing quality work.

© Nextlint_2023 All Rights Reserved

Privacy Policy Terms of Use