在这种情况下我可以使用什么模式或技术?

问题描述 投票:0回答:1

下面的代码是困扰我好几天的一个小例子:如何更改这个可变引用结构体的字段值?.

我第一次自己编写一个小应用程序,它遵循“干净的架构”逻辑,就像我对其他语言所做的那样(收集垃圾)。

你能帮我理解我做错了什么以及我可以使用什么更好的模式(我正在考虑构建器模式,但也考虑了各种设置器方法,这些方法允许我在需要时在多个地方更改值) ?

我想要实现的最大的便利就是能够使用这样的代码:

if let Some(condition) = &mut input.condition {
    condition.set_subscribed_at_is_nil(true);
} else {
    input.condition = Some(PlayerConditions::new().unset_subscribed_at_is_nil());
}

或更好:

input.condition.unwrap_or_default().set_subscribed_at_is_nil(true);

// or maybe input.condition = input.condition.unwrap_or_default().set_subscribed_at_is_nil(true);

if something_happened {
    input.condition.unset_it().set_another(Some("something"));
}

if something_else_happened {
    input.condition.set_another(Some("something")).check_something();
}

你有什么建议?

代码:

/*
[dependencies]
tokio = { version = "1", features = ["full"] }
*/

#[derive(Debug, Default)]
pub struct PlayerConditions {
    id: Option<String>,
    name: Option<String>,
    subscribed_at_is_nil: Option<bool>,
}

impl PlayerConditions {
    pub fn new() -> Self {
        Self::default()
    }
    pub fn is_default(&self) -> bool {
        self.id.is_none() && self.name.is_none() && self.subscribed_at_is_nil.is_none()
    }
    pub fn id(&self) -> &Option<String> {
        &self.id
    }
    pub fn set_id(&mut self, id: Option<String>) -> &mut Self {
        self.id = id;
        self
    }
    pub fn name(&self) -> &Option<String> {
        &self.name
    }
    pub fn set_name(&mut self, name: Option<String>) -> &mut Self {
        self.name = name;
        self
    }
    pub fn subscribed_at_is_nil(&self) -> &Option<bool> {
        &self.subscribed_at_is_nil
    }
    pub fn set_subscribed_at_is_nil(&mut self, subscribed_at_is_nil: Option<bool>) -> &mut Self {
        self.subscribed_at_is_nil = subscribed_at_is_nil;
        self
    }
}

#[derive(Debug, Default)]
pub struct PlayerListInput {
    pub condition: Option<PlayerConditions>,
    // This is not String: is a struct in real code
    pub order: Option<String>,
    // other fields here...
}

#[derive(Debug)]
pub struct DBPlayer {
    pub id: String,
    pub name: Option<String>,
    // For simplicity this is String in this example
    pub subscribed_at: Option<String>,
}

impl DBPlayer {
    fn query_construction<'a>(
        condition: Option<&'a mut PlayerConditions>,
        order: &Option<String>,
    ) -> String {
        // Sometimes I need to change condition here (so I need the mutability of it)

        let query = "SELECT * FROM players".to_string();

        if let Some(condition) = condition {
            if !condition.is_default() {
                // query = condition.add_each_one_to(query);
            }
        }

        if let Some(_order) = &order {
            // add order to query
        }

        query.to_string()
    }

    pub async fn query(
        _db: &str,      // This is not String: is a connection/transaction in real code
        input: &mut PlayerListInput,
    ) -> Vec<DBPlayer> {
        // Sometimes I need to change input here (so I need the mutability of it)

        let _query = Self::query_construction(input.condition.as_mut(), &input.order);

        let players = vec![]; // fetch_them_from_db_using_query_here;

        players
    }
}

async fn players_from_repo(input: &mut PlayerListInput) -> Vec<DBPlayer> {
    // Here I need to change input checking if something is already added, for example:

    if let Some(condition) = &mut input.condition {
        condition.set_subscribed_at_is_nil(Some(true));
    } else {
        input.condition = Some(PlayerConditions::new().set_subscribed_at_is_nil(Some(true)));
    }

    DBPlayer::query( "db_connection", input).await
}

#[tokio::main]
async fn main() {
    let mut input = PlayerListInput::default();

    let players = players_from_repo(&mut input).await;

    // I still need input ownership here
    dbg!(input);

    dbg!(players);
}
rust design-patterns builder-pattern
1个回答
0
投票

简单来说:

if let Some(condition) = &mut input.condition {
    condition.set_subscribed_at_is_nil(Some(true));
} else {
    let mut new_condition = PlayerConditions::new();
    new_condition.set_subscribed_at_is_nil(Some(true));
    input.condition = Some(new_condition);
}

是的,它有点长,但它非常清晰,我们并不总是需要最短的代码。

© www.soinside.com 2019 - 2024. All rights reserved.