クリーンアーキテクチャについて自分用にざっくりまとめる


## 参考
> - https://github.com/nrslib/play-clean-java

## 各レイヤー

### 1. Entities

- ビジネスルールをカプセル化したもの
- ドメイン
- 運送アプリだったら、運送の世界がオブジェクト

### 2. Use Cases

- ビジネスを表現したオブジェクト
- 買い物するときの受注だったり購入。カートがEntities。

### 3.Interface Adapters

- Controllers, Presenters, Gatewaysに分けられる。
- ゲームでいう、コントローラとかディスプレイ

### 4. Frameworks & Drivers

- 詳細なコード
- ビジネスロジックがこれに依存しないようにする

## それぞれの関係を図に表すと

### 処理の流れ

![clean-architecture-img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828785/8ca751e2-24de-6730-ebd1-7ed3e5bfaba6.png)

### より詳細な処理の流れ

![clean-architecture-img-detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828785/295ffb14-3b24-7562-f8d5-4fe4845d066b.png)

## 実装例 (サンプル: ユーザー作成機能)

### 1. Controller

```java
public class UserController {
  @Inject
  private UserAddUseCase addUserCase;

  public void createUser(String name, String roleId) {
    UserRole role = convertRole(roleId);
    // アプリケーションが求めるデータに変換する
    UseAddInputData inputData = new UserAddInputData(name, role);
    addUseCase.handle(inputData);
  }

  private UserRole convertRole(String roleId) {
    switch (roleId) {
      case "admin": return UserRole.ADMIN;
      case "member": return UserRole.MEMBER;
      default: throw new RuntimeException();
    }
  }
}
```

### 2. Input Data<DS> ※DTOと一緒

```java
public class UserAddInputData implements InputData<UserAddInputData> {
  private final String userName;
  private final UserRole role;

  public UserAddInputData(String userName, UserRole role) {
    this.userName = userName;
    this.role = role;
  }

  public String getUserName() { return userName; }

  public UserRole getUserRole() { return role; }
}

```

### 3. Input Boundary<I>

```java
public interface UserAddUseCase {
  void handle(UserInputData inputData);
}
```

### 4. Use Case Interator

```java
@Transactional
public class UserAddInterator implements UserAddUseCase {
  @Inject
  private UserRepository userRepository;

  @Inject
  private UserAddPresenter userAddPresenter;

  @Override
  public void handle(UserInputData userInputData) {
    String uuid = UUID.randomUUID().toString();

    User user = new User(
      new UserId(uuid),
      new UserName(inputData.getUserName()),
      inputData.getRole()
    );

    userRepository.save(user);

    UserAddOutputData outputData = new UserAddOutputData(uuid);
    userAddPresenter.output(outputData);
  }
}
```

### 5. Data Access Interface<I>

```java
public interface UserRepository {
  public void save(User user);
  public void remove(User user);
  public List<User> findAll();
  public Optional<User> find(UserId id);
}

```

### 6. Data Access

- サンプルはEBean
- 実装は直打ちでもEntityも再構築が出来ればなんでもok

```java
// EBean
public class EBeanUserRepository implements UserRepository {
  @Override
  public void save(User user) {
    UserId id = user.getId();
    models.User userData = Optional
                            .onNullable(models.User.find.byId(id.getValue()))
                            .orElseGet(() -> createNew(id, user.getRole()));

    userData.setName(user.getName().getValue());

    models.User.db().save(userData);
  }
}

```

### 7. Entities

- 注文の処理やカートに入れる処理

```java
public class User {
  private UserId id;
  private UserName name;
  private UserRole role;

  public User(UserId id, UserName name, UserRole role) {
    this.id = id;
    this.name = name;
    this.role = role;
  }

  public UserId getId() {
    return id;
  }

  public UserName getName() {
    return name;
  }

  public UserRole getRole() {
    return role;
  }

  public void changeName(UserName name) {
    this.name = name;
  }
}

public class UserName() {
  private String value;

  public UserName(String value) {
    if (value.length() < 3>) throw new RuntimeException();
    if (value.length() > 10) throw new RuntimeException();

    this.value = value;
  }

  public String getValue() {
    return value;
  }
}

```

### 8. Output Data<DS>

```java
public class UserAddOutputData implements OutputData {
  private String createdId;

  public UserAddOutputDate(String createId) {
    this.createdId = createId;
  }

  public String getCreatedId() {
    return createdId;
  }
}

```

### 9. Output Boundary

```java
public interface UserAddPresenter {
  public void output(UserAddOutputData);
}

```

### 10. Presenter

```java
public class ConsoleUserAddPresenter implements UserAddPresenter {
  private ConsoleView = new ConsoleView();

  public void output(UserAddOutputData outputData) {
    String userUuid = outputData.getCreatedId();
    ConsoleViewModel viewModel = new ConsoleViewModel(userUuid);
    consoleView.showCreatedUserId(viewModel);
  }
}

```

### 11. View Model<DS>

- 実際にデータを出力するのではなく、データの変換をしてあげる