エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

DCIの翻訳の翻訳、あるいは写経の写経

形から入る主義です。


id:yojikさんが書かれたコードをさらに写経。

一部、言語の制約とかで手を加えていますが、ほとんど直訳です。
中身はあとでもう一度考察する。


DCIアーキテクチャは、まだ読んでる途中。英語力のなさに悲しくなる。


勉強中につき突っ込み歓迎、大歓迎。


以下コード。

#include <iostream>
#include <sstream>
#include <string>
#include <typeinfo>

class Context;

template<typename T>
class Role
{
public:
    virtual ~Role() {}
    virtual Role& apply(T* t) = 0;
    virtual Role& on(Context* context) = 0;
};

template<typename T>
class Roles
{
public:
    Roles(T* target) : target_(target), role_(0) {}

    ~Roles()
    {
        delete role_;
    }

    template<typename R>
    R& as()
    {
        R* result = new R;
        delete role_;
        role_ = result;
        role_->apply(target_);
        return *result;
    }

private:
    T*       target_;
    Role<T>* role_;
};

class Account
{
public:
    Account(const std::string& accountNumber) : role_(new Roles<Account>(this)), 
                                                accountNumber_(accountNumber), 
                                                balance_(10000) {}
    ~Account() { delete role_; }

    std::string accountNumber() const { return accountNumber_; }
    Roles<Account>& role()            { return *role_;         }
    int& balance()                    { return balance_;       }
    const int& balance() const        { return balance_;       }

private:
    Roles<Account>* role_;
    std::string     accountNumber_;
    int             balance_;
};

class Context
{
public:
    virtual ~Context() {}
    virtual void show(const std::string& s) = 0;
};

class TargetAccount : public Role<Account>
{
public:
    void deposit(int amount)
    {
        account_->balance() += amount;
    }

    TargetAccount& apply(Account* account)
    {
        account_ = account;
        return *this;
    }

    TargetAccount& on(Context* context)
    {
        context_ = context;
        return *this;
    }

private:
    Account* account_;
    Context* context_;
};

class SourceAccount : public Role<Account>
{
public:
    void transferTo(TargetAccount& target, int amount)
    {
        withdraw(amount);
        target.deposit(amount);
    }

    void withdraw(int amount)
    {
        account_->balance() -= amount;
    }

    SourceAccount& apply(Account* account)
    {
        account_ = account;
        return *this;
    }

    SourceAccount& on(Context* context)
    {
        context_ = context;
        return *this;
    }

private:
    Account* account_;
    Context* context_;
};

class AccountView : public Role<Account>
{
public:
    void show()
    {
        std::ostringstream oss;
        oss << account_->accountNumber() << " -> " << account_->balance();
        context_->show(oss.str());
    }

    AccountView& apply(Account* account)
    {
        account_ = account;
        return *this;
    }

    AccountView& on(Context* context)
    {
        context_ = context;
        return *this;
    }

private:
    Account* account_;
    Context* context_;
};

class TransferUsecase : public Context
{
public:
    void execute(const std::string& a, const std::string& b, int money)
    {
        Account* accountA = find(a);
        Account* accountB = find(b);

        SourceAccount& source = accountA->role().as<SourceAccount>().on(this);
        TargetAccount& target = accountB->role().as<TargetAccount>().on(this);
        source.transferTo(target, money);

        AccountView& fview = accountA->role().as<AccountView>().on(this);
        AccountView& tview = accountB->role().as<AccountView>().on(this);

        fview.show();
        tview.show();

        delete accountA;
        delete accountB;
    }

    void show(const std::string& s)
    {
        std::cout << s << std::endl;
    }

    Account* find(const std::string& accountNumber)
    {
        return new Account(accountNumber);
    }
};

int main(int, char* [])
{
    TransferUsecase transferUsecase;
    transferUsecase.execute("1111", "2222", 3000);

    return 0;
}