LoginSignup
3
6

More than 5 years have passed since last update.

クリーンアーキテクチャ+DDDでAndroidアプリを作る(破)

Last updated at Posted at 2016-12-29

背景

 前回に引き続き、今回はクリーンアーキテクチャを実現するためのフレームワークについて考える。
 前回:クリーンアーキテクチャ+DDDでAndroidアプリを作る(序)

成果物 ( java, androidで使えるフレームワーク )

 まず「クリーンアーキテクチャをどう実現するか」に対する私見を述べる。
 開発当初からフレームワークによってクリーンアーキテクチャの思想を支えておけば、あらゆる場面で様々な恩恵を受けることができるのではないか、というものだ。
 そこで生み出したものがこちら。

 Foca:https://github.com/y-takano/Foca
(ライブラリ設定や実際の使い方は上記のページから。)

2017/05/07 投稿からすっかり時間がたってしまったが元の作りだと何の役にも立たなかったので一から考え直して全面改修・ドキュメント整備をした。

何故フレームワークが必要なのか

Untitled bbbbbbbb.png

 クリーンアーキテクチャに沿ったアプリケーションを保守していくためには、始めからこの思想を組んだ作りこみをしていく必要がある。
 
 かといってアプリケーションを開発するにあたり、クリーンアーキテクチャのあるべき姿をあーでもないこーでもないと考えながらクラスの設計や実装をしていくのはやはり効率が悪い。
 
 以上の対策として、DIコンテナのフレームワークが最適なのでは思われる。

Focaが持つ役割

 Focaフレームワークのあるべき姿を絵にかいてみる。

概念図

Untitled (1)ああああ.png

 クリーンアーキテクチャで指摘されている問題から、自分で書いた絵と照らしてフレームワークの持つべき機能を分析する。

問題領域 解決手段 実現すべき機能 重要度
1.業務層がアダプタ層に依存する DIP PresenterのDI 最高
2.業務層がDB環境に依存する DIP GatewayのDI 最高
3.アダプタ層が基盤環境に依存する DIP ViewのDI
4.横断的関心事が外部環境に依存する DIP+AOP AspecterのDI
5.外側のロジックが業務層に依存する 生成ロジックの分離 ControllerのDI

(用語)
・DIP ・・・ 依存関係逆転の原則(Dependency Inversion Principle)
・AOP ・・・ アスペクト指向プログラミング(Aspect Oriented Programming)
・DI ・・・ 依存性の注入(Dependency Injection)

以上の考え方で果たしてクリーンアーキテクチャの思想を支えるフレームワークになっているのか、実際に使ってみて検証する。

使ってみる

まず、XMLとAPIの利用で以下を実現するための設計をする。

Untitled (1)asdasda.png

↓ この仕組みを維持することでクリーンアーキテクチャのレイヤ化を実現する。

CleanArchitecture.jpg

↓ この仕組みを実装する。

DIコンテナ定義(XML)

foca-dicon.xml
<?xml version="1.0" encoding="UTF-8"?>

<!-- LayerContext: アプリケーションの定義
 schemaLocationで示したurlにアクセスすることで、githubにあるxsdと連携して検証することができる。
-->
<LayerContext 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.java_conf.gr.jp/ke/namespace/foca" 
xsi:schemaLocation="http://www.java_conf.gr.jp/ke/namespace/foca https://raw.githubusercontent.com/y-takano/Foca/master/foca-dicon.xsd">

    <!-- Logger: ロガーの定義
     アプリケーションから名前を指定して使用する. 複数定義可.
    -->
    <Logger level="DEBUG" name="tracelog" class="..."/>

    <!-- Aspect: アスペクト(横断的関心事)の定義
     Controller,Presenter,Gatewayをjoinpointするadviceを指定. 複数定義可.
    -->
    <Aspect name="trace-advice" advice="..."/>

    <!-- DataFlow: InterfaceAdapterの定義
     Controller,Presenter,Gatewayの依存性を指定. 複数定義可.
    -->
    <DataFlow type="UI" name="test">
        <Controller>
            <InputPort />
            ...
        </Controller>
        <Presenter>
            <View />
            ...
        </Presenter>
    </DataFlow>

    <!-- DataFlow: Gatewayを定義する場合 -->
    <DataFlow type="DB" name="db-stub">
        <Gateway>
            <Driver />
            ...
        </Gateway>
        <Gateway>
            <InputPort />
            ...
        </Gateway>
    </DataFlow>

</LayerContext>

アプリケーション実装( java )

外層の実装
public class Outside {

    // DIコンテナ定義を読み込む
    Foca.updateDefault(new URL("xxx"));

    // インスタンスへDI
    SomeObj obj = new SomeObj();
    Foca.getDefault().inject(obj);

    // DI済インスタンスを生成
    SomeObj obj = Foca.getDefault().createInstance(SomeObj.class);
}
UIハンドラの実装
public class SampleEventHandler {

    // Controllerの宣言
    @Controller(name = "test")
    private InterfaceAdapter controller;

    // Loggerの宣言
    @Log
    private Logger logger;

    // イベントハンドルメソッド
    public void handle() {

        // Logger呼出
        logger.debug("debugログ");
        logger.info("infoログ");

        // Controller呼出
        Data dto = new Data();
        controller.invoke(dto);
    }
}
Usecaseの実装
public class SampleUsecase {

    // Presenterの宣言
    @Presenter(name = "test")
    private InterfaceAdapter presenter;

    // Gatewayの宣言
    @Gateway(name = "test-db")
    private InterfaceAdapter gateway;

    // InputPortの宣言
    @InputPort
    public void execute(Data dto) {

        // Gateway呼出
        gateway.invoke();

        // Presenter呼出
        presenter.invoke();
    }
}
Driverの実装
public class SampleDriver {

    // Gatewayの宣言
    @Gateway(name = "test-db")
    private InterfaceAdapter gateway;

    // Driverの宣言
    @Driver
    public void access(Data dto) {

        // Gateway呼び出し
        gateway.invoke(...);
    }
}
Presenterの実装
public class SamplePresenter {

    // Viewの宣言
    @View
    public void print(Data dto) {
        ...
    }
}

これで、レイヤ毎に疎結合されたモジュールが実装できた。

性能や利便性はともかくとして、クリーンアーキテクチャで謳われている、独立性・再利用性の網羅はできているのではないか。


次回はアプリケーション本体について考えたい。

3
6
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
3
6