Edited at

[Swift版]クリーンアーキテクチャ実践編①(Domain層)

More than 3 years have passed since last update.


はじめに

最近巷で、熱い『クリーンアーキテクチャ』を社内案件でも導入しています。

まだまだ不完全な部分も多いので、今一度整理してみました。

今回はDomain層を中心に纏めてみました。


やること



  • UI層


    • View

    • ViewController

    • Presenter




  • Domain層


    • Usecase ← ここ説明します

    • Repository ← ここ説明します

    • Entity ← ここ説明します




  • Data層


    • Repository ← ここ説明します

    • Entity

    • DataStore




やらないこと

・クリーンアーキテクチャーの概念について

・UI層について

・Data層について(Repositoryを除く)


ご説明する例

Usecaseからユーザ情報にアクセスする際の事例

レイヤ
カテゴリ
クラス名
説明

Domain層
Entity
User
ユーザ情報を管理するクラス(メールアドレス、誕生日)

Repository
UserRepository
ユーザ情報とのインターフェース

Usecase
UserUsecase
業務ロジッククラス

Data層
Repository
UserRepositoryImpl
ユーザ情報へアクセスする実体のクラス


1. Domain層のEntityについて

ユーザ情報として、メールアドレスと誕生日を保持するクラス


User.swift

import Foundation

class User: NSObject {
var mailAddress = ""
var birthDay = ""
}



2. Domain層のRepositoryについて

ユーザ情報へアクセスする手段を纏めたインターフェース(プロトコル)

DAOに近いイメージ???

利用する側は、どこに保存されているかは意識しない。


UserRepository.swift

import Foundation

protocol UserRepository: class {
func store(user: User)
func user(userID: NSInteger) -> User
func users() -> [User]
func delete(userID: NSInteger)
}



3. Data層のRepositoryについて

UserRepositoryプロトコルを実装したクラス

ユーザ情報の保存先は、仕様に合わせて、アプリ内でも、サーバーサイドでも良い。


UserRepositoryImpl.swift

class UserRepositoryImpl: UserRepository {

func store(user: User) {
//TODO: ユーザ情報をどこかに保存する
}

func user(userID: NSInteger) -> User {

//TODO: ユーザ情報をどこかから取得する
return User()
}

func users() -> [User] {

//TODO: ユーザ情報をどこかから取得する
return []
}

func delete(userID: NSInteger) {
//TODO: どこかに保存しているユーザ情報を削除する
}
}



4. Domain層のUsecaseについて


UserUsecase.swift

import Foundation

class UserUsecase: NSObject {

let repository: UserRepository

init(repository: UserRepository) {
self.repository = repository
super.init()
}

//メールアドレスを保存する
func storeMailAddressByID(userID: NSInteger, mailAddress: String) {

let user = repository.user(userID)
user.mailAddress = mailAddress
repository.store(user)
}

//メールアドレスを取得する
func findMailAddressByID(userID: NSInteger) -> String {
return repository.user(userID).mailAddress
}

//誕生日を保存する
func storeBirthDayByID(userID: NSInteger, birthDaty: String) {

let user = repository.user(userID)
user.birthDay = birthDaty
repository.store(user)
}

//誕生日を取得する
func findBirthDayByID(userID: NSInteger) -> String {
return repository.user(userID).birthDay
}
}



まとめ

ポイントは、Domain層のRepositoryだと思います。


  1. データにアクセスするためには、Domain層のRepositoryを通してアクセスする。


  2. データにアクセスするクライアントは、保存先がサーバー(API経由)なのかアプリ内(CoreData、UserDefaultsなど)か意識しない。


誤りやもっとこうしたほうが良いとというアドバイスがございましたら、ご指摘頂けますと幸いです。

こちらも合わせて読んで頂ければ幸いです。

[Swift版]クリーンアーキテクチャ実践編②(Data層)


謝辞

@KentaKudoさん、ご指摘ありがとうございます。

依存性の注入(Dependency Injection)の観点で、

柔軟性がない、テストしにくいため、

UserUsecaseを修正しました。