NeuroWhAI의 잡블로그

[Rust] 데코레이터 패턴 본문

개발 및 공부/설계

[Rust] 데코레이터 패턴

NeuroWhAI 2018. 12. 30. 14:46


데코레이터 패턴으로 HTML 코드를 표현한 예제입니다.


https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b0fb18d31a6e4da32f135a3970985efc

trait Element {
    fn outer_html(&self) -> String;
}


struct Content {
    content: String
}

impl Content {
    fn new(content: &str) -> Content {
        Content {
            content: content.into()
        }
    }
}

impl Element for Content {
    fn outer_html(&self) -> String {
        self.content.clone()
    }
}


struct Tag<T: Element> {
    name: String,
    element: T,
}

impl<T: Element> Tag<T> {
    fn new(name: &str, element: T) -> Self {
        Tag {
            name: name.into(),
            element,
        }
    }
}

impl<T: Element> Element for Tag<T> {
    fn outer_html(&self) -> String {
        format!("<{name}>{content}</{name}>",
            name = self.name,
            content = self.element.outer_html())
    }
}


struct Font<T: Element> {
    element: T,
    size: Option<usize>,
    color: Option<String>,
    face: Option<String>,
}

impl<T: Element> Font<T> {
    fn new(element: T) -> Self {
        Font {
            element,
            size: None,
            color: None,
            face: None,
        }
    }
}

impl<T: Element> Font<T> {
    #[allow(dead_code)]
    fn size(mut self, size: usize) -> Self {
        self.size.replace(size);
        self
    }
    
    #[allow(dead_code)]
    fn color(mut self, color: &str) -> Self {
        self.color.replace(color.into());
        self
    }
    
    #[allow(dead_code)]
    fn face(mut self, face: &str) -> Self {
        self.face.replace(face.into());
        self
    }
}

impl<T: Element> Element for Font<T> {
    fn outer_html(&self) -> String {
        let mut att = "".to_string();
        if let Some(size) = &self.size {
            att.push_str(&format!(" size=\"{}\"", size));
        }
        if let Some(color) = &self.color {
            att.push_str(&format!(" color=\"{}\"", color));
        }
        if let Some(face) = &self.face {
            att.push_str(&format!(" face=\"{}\"", face));
        }
        
        let inner_html = self.element.outer_html();
        format!("<font{}>{}</font>", att, inner_html)
    }
}


fn main() {
    /*let content = Content::new("Hello, World!");
    let bold_content = Tag::new("b", content);
    let font_bold_content = Font::new(bold_content)
        .size(42).color("gray");
    let div_font_bold_content = Tag::new("div", font_bold_content);*/
    
    let html = Tag::new("body",
        Font::new(
            Tag::new("b",
                Content::new("Hello, World!")
            )
        )
        .size(42)
        .color("gray")
    );
    
    println!("{}", html.outer_html())
}
Hello, World!


와!

다른 글 보고 심심하던 참에 해봤습니다.

...

아무리 다른 언어로 해봤던 패턴이라도 언어 자체에서 차이가 나니까 구현도 좀 차이가 나는 것 같네요.


그나저나 데코레이터 패턴 보면서 느끼는 건데 컴포지트 패턴이랑 비슷한 것 같지 않아요?

어떤 공통의 인터페이스를 구현하고 그 구현체 중 일부가 멤버로 해당 인터페이스를 구현한 다른 녀석을 가질 수 있다는 점에서...

아님 말고 ^^



Comments