Rust - Virtual Constructor, Factory Method

Rust has no overloading, no extension functions, and no default parameters! Is Rust a piece of shit?

我要实现一个Builder,然后这个Builder有同样名字不同参数的一个方法作为创建builder的入口方法。

场景是一Sql连接器,可以根据输入的参数自动判断选择的Sql类型 例如只有一个字符串输入叫做Sqlite,多个字符串输入,又有端口又有用户名密码和数据库名称的这种,就是MySql。

众所周知Rust的一个方法,不能重复名字,即使他们的入参不同,众所周知有一个设计模式叫什么工厂模式()奇奇怪怪的名字而已。

那么根据这个情况,你可以获得两个struct + 一坨代码:

pub trait DBConnection {
	// your db action
}

pub struct Sqlite { path: String }
pub struct Mysql { host: String, port: u16, user: String, password: String, db: String }

impl DBConnection for Sqlite {}
impl DBConnection for Mysql {}

按理说,我看见大部分的Rust项目都会获得如下代码:

pub fn new_sqlite_connection_factory(path: String) 
-> Box<dyn SqlConnectionFactory<String>> 
{
    Box::new(Sqlite { path })
}

pub fn new_mysql_connection_factory(host: String, port: u16, user: String, password: String, db: String) 
-> Box<dyn SqlConnectionFactory<(String, u16, String, String, String)>> 
{
    Box::new(Mysql { host, port, user, password, db })
}

如此丑陋,而且名称也不一样,让我很难受,直观倒是非常...

工厂模式设计

通过简化设计,我们可用得到如下代码:

pub trait DBConnection {}

pub trait SqlConnectionFactory<T> {
    fn new_db_connection(&self, params: T) -> Box<dyn DBConnection>;
}
pub struct DBConnectorFactory;

pub struct Sqlite { path: String }
pub struct Mysql { host: String, port: u16, user: String, password: String, db: String }

impl DBConnection for Sqlite {}
impl DBConnection for Mysql {}

impl SqlConnectionFactory<String> for DBConnectorFactory {
    fn new_db_connection(&self, params: String) -> Box<dyn DBConnection> {
        Box::new(Sqlite { path: params })
    }
}

impl SqlConnectionFactory<(String, u16, String, String, String)> for DBConnectorFactory {
    fn new_db_connection(&self, params: (String, u16, String, String, String)) -> Box<dyn DBConnection> {
        Box::new(Mysql { host: params.0, port: params.1, user: params.2, password: params.3, db: params.4 })
    }
}

#[tokio::main]
async fn main() {
    let factory = DBConnectorFactory{};
    let sqlite_factory = factory.new_db_connection(".".to_string());
    let mysql_factory = factory.new_db_connection(("127.0.0.1".to_string(), 8080, "root".to_string(), "123456".to_string(), "root".to_string()));
}