Builder

godo·2022년 8월 15일
0

Swift - Design Patterns

목록 보기
2/24

초기화시 한 번에 너무 많은 인자를 한꺼번에 주게 된다면 당연히 비효율적이게 되겠죠.
이때 사용하는 방식입니다.

Without Builder

func main()
{
    let hello = "hello"
    var result = "<p>\(hello)</p>"
    print(result)
    
    let words = ["hello","world"]
    result = "<ul>\n"
    for word in words
    {
        result.append("<li>\(word)</li>\n")
    }
    
    result.append("</ul>")
    
    print(result)
}

main()

Bulider

class HtmlElement: CustomStringConvertible
{
    var name = ""
    var text = ""
    var elements = [HtmlElement]()
    private let indentSize = 2
    
    init() {}
    init(name: String, text: String)
    {
        self.name = name
        self.text = text
    }
    
    private func description(_ indent: Int) -> String
    {
        var result = ""
        let i = String(repeating: " ", count: indent)
        result += "\(i)<\(name)>\n"
        
        if !text.isEmpty
        {
            result += String(repeating: " ", count: (indent+1))
            result += text
            result += "\n"
        }
        
        for e in elements
        {
            result += e.description(indent+1)
        }
        result += "\(i)</\(name)>\n"
        
        return result
    }
    
    public var description: String
    {
        return description(0)
    }
}


class HtmlBuilder: CustomStringConvertible
{
    private let rootName : String
    var root = HtmlElement()
    
    init(rootName: String)
    {
        self.rootName = rootName
        root.name = rootName
    }
    
    func addChild(name: String, text: String)
    {
        let e = HtmlElement(name: name, text: text)
        root.elements.append((e))
    }
    
    var description: String
    {
        return root.description
    }
    
    func clear()
    {
        root = HtmlElement(name: rootName, text: "")
    }
}


func main()
{

    
    let builder = HtmlBuilder(rootName: "ul")
    builder.addChild(name: "li", text: "hello")
    builder.addChild(name: "li", text: "word")
    print(builder)
}

Fluent Builder

func addChildFluent(name: String, text: String) -> HtmlBuilder
{
    let e = HtmlElement(name: name, text: text)
    root.elements.append((e))
    return self
}

... 

builder.addChildFluent(name: "li", text: "hello")
       .addChild(name: "li", text: "word")

이런 식으로도 코드를 구현하는 게 가능합니다.

Faceted Builder

class Person : CustomStringConvertible
{
    // address
    var streetAddress = "", postcode = "", city = ""
    
    
    // employment
    var companyName = "", position = ""
    var annualIncome = 0
    
    
    var description: String
    {
        return "I live at \(streetAddress), \(position), \(city)." +
        "I work at \(companyName) as a \(position), earning \(annualIncome)"
    }
}

class PersonBuilder
{
    var person = Person()
    
    var lives : PersonAddressBuilder
    {
        return PersonAddressBuilder(person)
    }
    
    var works : PersonJobBuilder
    {
        return PersonJobBuilder(person)
    }
    
    func build() -> Person
    {
        return person
    }
}

class PersonJobBuilder : PersonBuilder
{
    internal init(_ person: Person)
    {
        super.init()
        self.person = person
    }
    
    func at(_ companyName: String) -> PersonJobBuilder
    {
        person.companyName = companyName
        return self
    }
    
    func asA(_ position: String) -> PersonJobBuilder
    {
        person.position = position
        return self
    }
    
    func earning(_ annualIncome: Int) -> PersonJobBuilder
    {
        person.annualIncome = annualIncome
        return self
    }
}


class PersonAddressBuilder : PersonBuilder
{
  internal init(_ person: Person)
  {
    super.init()
    self.person = person
  }
  func at(_ streetAddress: String) -> PersonAddressBuilder
  {
    person.streetAddress = streetAddress
    return self
  }
  func withPostcode(_ postcode: String) -> PersonAddressBuilder
  {
    person.postcode = postcode
    return self
  }
  func inCity(_ city: String) -> PersonAddressBuilder
  {
    person.city = city
    return self
  }
}

func main()
{
    let pb = PersonBuilder()
    let p = pb
        .lives.at("123 Seoul road")
        .inCity("Seoul")
        .withPostcode("753")
        .works.at("A Company")
        .asA("developer")
        .earning(1000)
        .build()
    print(p)
}

정리

Builder 을 사용하면 좀 더 보기 좋게 초기화를 할 수 있습니다.

profile
☀️☀️☀️

0개의 댓글