빌더 패턴
2001년과 같은 중매
우리는 Cake의 John McCrea가 약간 비꼬고 이상한 꿈을 꾸는 여자를 찾도록 도울 것입니다. 그는 특별한 사람입니다.
네, 여러분과 저는 모두 그렇게 생각합니다. 이것은 Rust 컴파일러의 작업처럼 들립니다. 이 밴드는 정말 시대를 앞서갔습니다. 문제를 모델링해 보겠습니다.
/// Girl type
struct Girl {}
impl Girl {
/// Construct a Girl
fn new() -> Self {
Self {}
}
}
/// Determine whether given girl matches spec
fn is_dream_girl(girl: &Girl) -> bool {
// we don't know anything about spec yet, so odds are no
false
}
fn main() {
let girl = Girl::new();
println!("Match: {}", is_dream_girl(&girl));
}
cargo run
와 함께 이것을 실행하면 예상되는 출력이 생성됩니다: Match: false
.
그래서, 우리가 구체적으로 무엇을 찾고 있습니까? 운 좋게도, 우리 남자는 선호도에서 바로 시작합니다. 첫 번째 줄에서 그는 "다이아몬드 같은 마음을 가진 여자"를 원한다고 말합니다. 테스트할 멤버 필드를 추가해 보겠습니다.
#[derive(Clone, Copy, PartialEq)]
enum Mind {
Computer,
Diamond,
Garden,
Scalpel,
Sieve,
Unknown,
}
struct Girl {
mind: Mind,
}
impl Girl {
fn new(mind: Mind) -> Self {
Self { mind }
}
}
이제 테스트 함수는 요청된 변형을 확인할 수 있습니다.
fn is_dream_girl(girl: &Girl) -> bool {
girl.mind == Mind::Diamond
}
fn main() {
let girl = Girl::new(Mind::Diamond);
println!("Match: {}", is_dream_girl(&girl));
}
엄청난! 이제 이 Match: true
를 전달할 때 Girl
를 얻습니다. 잠깐만요. 몇 가지 기준이 더 있습니다. 다음으로 "최고를 아는 소녀"가 필요합니다. 그것은 아주 쉽습니다. 그녀가 하든 하지 않든:
struct Girl {
mind: Mind,
knows_best: bool,
}
impl Girl {
fn new(mind: Mind, knows_best: bool) -> Self {
Self { mind, knows_best }
}
}
fn is_dream_girl(girl: &Girl) -> bool {
girl.mind == Mind::Diamond && girl.knows_best
}
매개변수 목록에 추가하기만 하면 됩니다.
fn main() {
let girl = Girl::new(Mind::Diamond, true);
println!("Match: {}", is_dream_girl(&girl));
}
그루비. 이제 우리는 "잘라진 신발과 담배처럼 타는 눈"이 필요합니다. 몇 가지 문자열 쌍을 연결해야 할 것 같습니다.
type Attribute = (String, String);
/// Girl type
struct Girl {
items: Vec<Attribute>,
mind: Mind,
knows_best: bool,
}
속성은 ("shoes", "cut")
와 같은 튜플입니다. 생성자에서 신발과 눈 속성을 요청할 수 있습니다.
impl Girl {
fn new(mind: Mind, knows_best: bool, shoes: &str, eyes: &str) -> Self {
let mut ret = Self {
items: Vec::new(),
mind,
knows_best,
};
ret.push_item("shoes", shoes);
ret.push_item("eyes", eyes);
ret
}
fn push_item(&mut self, item_name: &str, attribute: &str) {
self.items.push((item_name.into(), attribute.into()));
}
}
우리는 우리가 원하는 것을 얻기 위해 항목을 확인할 것입니다:
fn is_dream_girl(girl: &Girl) -> bool {
let mut found_shoes = false;
let mut found_eyes = false;
for item in &girl.items {
if item.0 == "shoes" && item.1 == "cut" {
found_shoes = true;
} else if item.0 == "eyes" && item.1 == "burn like cigarettes" {
found_eyes = true;
}
}
girl.mind == Mind::Diamond && girl.knows_best && found_shoes && found_eyes
}
대박! 새 속성으로 Girl
를 구성하기만 하면 됩니다.
fn main() {
let girl = Girl::new(Mind::Diamond, true, "cut", "burn like cigarettes");
println!("Match: {}", is_dream_girl(&girl));
}
괜찮아. 기다리다. 여기서 문제가 보이나요? 미리 훑어보자...
I want a girl with the right allocations
Who's fast and thorough
And sharp as a tack
She's playing with her jewelry
She's putting up her hair
She's touring the facility
And picking up slack
...
그것은 거기에서 계속됩니다! 이 Girl
생성자는 이미 손을 떼고 있으며 첫 번째 스탠자에서 겨우 겨우 만들었습니다. 존이 마음을 바꾼다면? 그는 무언가가 그다지 중요하지 않다고 판단하거나 새로운 기준을 추가할 수 있습니다. 이 코드는 그런 변경을 할 수 없습니다. 모든 호출 사이트는 이 정확한 순서로 제공된 이 정확한 매개변수 목록에 의존하지만 사람들은 그렇게 작동하지 않습니다. 모든 종류의 변형이 있을 수 있습니다.
패턴
빌더 패턴을 활용하여 이 프로그램을 다시 구현해 보겠습니다. Girl
가 처음 생성될 때, 우리는 단지 몇 가지 합리적인 기본값으로 시작하기를 원합니다:
struct Girl {
items: Vec<Attribute>,
mind: Mind,
knows_best: bool,
}
impl Girl {
fn new() -> Self {
Self::default()
}
}
impl Default for Girl {
fn default() -> Self {
Self { mind: Mind::Unknown, knows_best: false, items: Vec::new() }
}
}
다른 모든 것은 백지입니다. 이런 식으로 매개변수 없이 Girl::new()
를 사용하고 시작점을 얻을 수 있습니다. 더 추가하려면 메서드를 정의할 수 있습니다.
impl Girl {
// ..
fn set_mind(&mut self, mind: Mind) -> &mut Self {
self.mind = mind;
self
}
}
이 메서드는 변경 가능한 참조를 가져와 하나를 반환하므로 먼저 구성하고 나중에 조정할 수 있습니다.
fn main() {
let mut girl = Girl::new();
girl.set_mind(Mind::Diamond);
println!("Match: {}", is_dream_girl(&girl));
}
나머지를 추가해 보겠습니다.
impl Girl {
fn push_item(&mut self, item_name: &str, attribute: &str) {
self.items.push((item_name.into(), attribute.into()));
}
fn toggle_knows_best(&mut self) -> &mut Self {
self.knows_best = !self.knows_best;
self
}
}
이제 우리는 생성 당시에 무엇을 알고 있었는지에 상관없이 한 번에 하나씩 추가할 수 있습니다.
fn main() {
let mut girl = Girl::new();
girl.set_mind(Mind::Diamond);
girl.toggle_knows_best();
girl.push_item("shoes", "cut");
girl.push_item("eyes", "burn like cigarettes");
println!("Match: {}", is_dream_girl(&girl));
}
사양이 증가하고 발전함에 따라 작업하기가 훨씬 쉽습니다.
더 복잡한 시나리오에서는 GirlBuilder와 같은 별도의 유형을 사용하고 각 단계에서 소유권을 가져와야 할 수 있습니다. 이렇게 하면 한 줄로 이 모든 작업을 수행할 수 있습니다. let girl = GirlBuilder::new().set_mind(Mind::Diamond).toggle_knows_best();
이렇게 하면 구성 옵션이 제한됩니다. 예를 들어 if
표현식에서 일부 빌더 메서드를 조건부로 호출하려는 경우입니다. 가능하다면 비소유 패턴이 더 유연합니다.
이 시간이 지난 후 McCrea 씨가 마침내 안정을 취하도록 도울 수 있기를 바랍니다.
도전
이 노래가 '올디'가 될 지금부터 5년을 준비하라.
Reference
이 문제에 관하여(빌더 패턴), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/deciduously/the-builder-pattern-249l
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
/// Girl type
struct Girl {}
impl Girl {
/// Construct a Girl
fn new() -> Self {
Self {}
}
}
/// Determine whether given girl matches spec
fn is_dream_girl(girl: &Girl) -> bool {
// we don't know anything about spec yet, so odds are no
false
}
fn main() {
let girl = Girl::new();
println!("Match: {}", is_dream_girl(&girl));
}
#[derive(Clone, Copy, PartialEq)]
enum Mind {
Computer,
Diamond,
Garden,
Scalpel,
Sieve,
Unknown,
}
struct Girl {
mind: Mind,
}
impl Girl {
fn new(mind: Mind) -> Self {
Self { mind }
}
}
fn is_dream_girl(girl: &Girl) -> bool {
girl.mind == Mind::Diamond
}
fn main() {
let girl = Girl::new(Mind::Diamond);
println!("Match: {}", is_dream_girl(&girl));
}
struct Girl {
mind: Mind,
knows_best: bool,
}
impl Girl {
fn new(mind: Mind, knows_best: bool) -> Self {
Self { mind, knows_best }
}
}
fn is_dream_girl(girl: &Girl) -> bool {
girl.mind == Mind::Diamond && girl.knows_best
}
fn main() {
let girl = Girl::new(Mind::Diamond, true);
println!("Match: {}", is_dream_girl(&girl));
}
type Attribute = (String, String);
/// Girl type
struct Girl {
items: Vec<Attribute>,
mind: Mind,
knows_best: bool,
}
impl Girl {
fn new(mind: Mind, knows_best: bool, shoes: &str, eyes: &str) -> Self {
let mut ret = Self {
items: Vec::new(),
mind,
knows_best,
};
ret.push_item("shoes", shoes);
ret.push_item("eyes", eyes);
ret
}
fn push_item(&mut self, item_name: &str, attribute: &str) {
self.items.push((item_name.into(), attribute.into()));
}
}
fn is_dream_girl(girl: &Girl) -> bool {
let mut found_shoes = false;
let mut found_eyes = false;
for item in &girl.items {
if item.0 == "shoes" && item.1 == "cut" {
found_shoes = true;
} else if item.0 == "eyes" && item.1 == "burn like cigarettes" {
found_eyes = true;
}
}
girl.mind == Mind::Diamond && girl.knows_best && found_shoes && found_eyes
}
fn main() {
let girl = Girl::new(Mind::Diamond, true, "cut", "burn like cigarettes");
println!("Match: {}", is_dream_girl(&girl));
}
I want a girl with the right allocations
Who's fast and thorough
And sharp as a tack
She's playing with her jewelry
She's putting up her hair
She's touring the facility
And picking up slack
...
struct Girl {
items: Vec<Attribute>,
mind: Mind,
knows_best: bool,
}
impl Girl {
fn new() -> Self {
Self::default()
}
}
impl Default for Girl {
fn default() -> Self {
Self { mind: Mind::Unknown, knows_best: false, items: Vec::new() }
}
}
impl Girl {
// ..
fn set_mind(&mut self, mind: Mind) -> &mut Self {
self.mind = mind;
self
}
}
fn main() {
let mut girl = Girl::new();
girl.set_mind(Mind::Diamond);
println!("Match: {}", is_dream_girl(&girl));
}
impl Girl {
fn push_item(&mut self, item_name: &str, attribute: &str) {
self.items.push((item_name.into(), attribute.into()));
}
fn toggle_knows_best(&mut self) -> &mut Self {
self.knows_best = !self.knows_best;
self
}
}
fn main() {
let mut girl = Girl::new();
girl.set_mind(Mind::Diamond);
girl.toggle_knows_best();
girl.push_item("shoes", "cut");
girl.push_item("eyes", "burn like cigarettes");
println!("Match: {}", is_dream_girl(&girl));
}
Reference
이 문제에 관하여(빌더 패턴), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/deciduously/the-builder-pattern-249l텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)