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()));
}