LoginSignup
8
4

More than 3 years have passed since last update.

Rustでクリーンアーキテクチャを組む時DIするサンプルコード

Posted at

はじめに

Rustでクリーンアーキテクチャを組もうとしていて、うまくレイヤーを分離できませんでした。
思想というよりは単にtraitやジェネリクスの正しい書き方を知らなかっただけでかなりの時間を要してしまったので、自分のメモを兼ねて書いてみようと思います。

構成としては
DB -> Repository -> Serviceというようなレイヤーがあった時に、いかに分離(=DI)するかを想定しています。

関連型 + 関連関数での実装


#[derive(Debug)]
struct User {
    age: u8
}

struct PgDatabase;

// 関連型を用いたトレイト
trait Repository {
// 関連型
    type CreateRequest;
    type CreateResponse;

// 関連関数
    fn create(request:Self::CreateRequest) -> Self::CreateResponse;
}

impl Repository for PgDatabase {
    // add code here
    type CreateRequest = u8;
    type CreateResponse = User;
    fn create(age: u8) -> User {
        User { age }
    }
}

struct Service<U:Repository>(U);

impl <U:Repository> Service<U>{
    pub fn new_with_age(&self, age: U::CreateRequest) -> U::CreateResponse {
        U::create(age)
    }
}

fn main() {
    let db: PgDatabase = PgDatabase;
    let service = Service::<PgDatabase>(db);
    let user = service.new_with_age(20);
    dbg!(user);
}

ジェネリクスとメソッドでの実装


#[derive(Debug, Clone, Copy)]
struct User {
    id: u16,
    age: u8
}

struct PgDatabase{
    // DB機能のモックです
    next_user_id: u16,
    users: Vec<User>
}

// generic trait
trait Repository<T,U,V> {
    fn create(&mut self, new_params:T) -> U;
    fn find_by_id(&self, id: V) -> Option<&U>;
}

impl Repository<u8, User, u16> for PgDatabase {
    // add code here
    fn create(&mut self, age: u8) -> User {
        let u = User{ age, id: self.next_user_id };
        self.next_user_id = self.next_user_id + 1;
        self.users.push(u);
        u
    }

    fn find_by_id(&self, id: u16) -> Option<&User> {
        self.users.iter().find(|user| { user.id == id })
    }
}

struct Service<U:Repository<u8, User, u16>>{
    repository: U
}

impl <U:Repository<u8, User, u16>> Service<U>{
    pub fn new_with_age(&mut self, age: u8) -> User {
        self.repository.create(age)
    }
}

fn main() {
    let db: PgDatabase = PgDatabase { next_user_id: 0, users: Vec::new()};
    let mut service = Service::<PgDatabase>{repository: db};
    let user = service.new_with_age(20);
    dbg!(user);
}

........その他はパターンを見つけ次第追記予定

終わりに

今の所2つのサンプルしかありませんが、他の実装パターンも追記予定です。
良くない書き方があるかと思いますので、お気づきの際にはご指摘いただければ幸いです。

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4