オブジェクト指向分析によるモジュール分割のイメージ


伝えたいこと

モデリングとプログラミングが関係ないと思っている人向けです。
オブジェクト指向分析モデリングの結果を実装すると、コードが読みやすくなります。
実際には、「オブジェクト指向分析」がモジュール分割の非常に有効な手段である、ということです。
今回は、「顧客がクリーニング店に洗濯物を出す」という内容を、分析モデリングし、その後コードに変換しています。

分析のクラス図

話を分かりやすくするために、クラス図はかなり小さなネタにしています。
クリーニング店と顧客の関係で、特に、顧客が衣服を行きつけのクリーニング店にクリーニングしてもらうという関係性だけを表しています。

見て分かるように、非常に素直に伝えたい人間関係やモノの関係を、ポンチ絵的に表した(クラス)図です。
これならば、プログラミングと関係なく、人と人が共有して話し合っても、話しやすい図になっているのではないでしょうか。

分析のシーケンス図

とても単純ですが、顧客がクリーニング店に行って、クリーニングしてもらう流れを描きました。
単純化するために、クリーニングは同期で書いてあります(つまり、クリーニングが終わるまでそこで待っている)ので、そこは突っ込まないでください(^^)。

そのモデルを、そのままコード

Program.csは、
クリーニング店と顧客のインスタンスを生成して、
顧客に、クリーニングの回数券を買わせ、
顧客に、服を汚させて、
次に、
顧客に、クリーニング店に行かせています。 // シーケンス図は、ここだけ描いてある。

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cleaners
{
    class Program
    {
        static void Main(string[] args)
        {
            // クリーニング店
            Cleaners cleaners = new Cleaners();
            // 行きつけのクリーニング店のある顧客
            Customer custmer = new Customer(cleaners);

            // 回数券を買う
            custmer.BuyCouponTicket();

            // 服を汚す
            custmer.StockDirtyLaundry();

            // クリーニング店に行く
            custmer.GoCleaners();
        }
    }
}

Custmer.csは、「顧客」クラスです。
クラス図を、まんま、コードに落としています。
サンプルプログラムなので、コンストラクタで、洋服を持たせてしまいましたが、ご愛敬としてください。
最後の関数「クリーニング店に行く」がシーケンス図で示したものです。
シーケンス図と比べると対応していると思います。

Custmer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cleaners
{
    // 顧客
    class Customer
    {
        // 行きつけのクリーニング店のある顧客
        public Customer(Cleaners regularCleaners)
        {
            RegularCleaners = regularCleaners;
            CleanLaundry.Add(new Clothes("T-Shirt"));
            CleanLaundry.Add(new Clothes("Jacket"));
        }

        // 汚れた洗濯物
        public List<Clothes> DirtyLaundry { get; } = new List<Clothes>();

        // 回数券
        private Queue<Coupon> CouponTicket { get; } = new Queue<Coupon>();

        // 行きつけのクリーニング店
        private Cleaners RegularCleaners = null;

        // きれいな洗濯物
        public List<Clothes> CleanLaundry { get; } = new List<Clothes>();

        // 汚れものを貯める
        public void StockDirtyLaundry()
        {
            // きれいな洗濯物をひとつ取り出して、
            Clothes clothes = CleanLaundry[0];
            CleanLaundry.RemoveAt(0);

            // その洗濯物を、汚れた洗濯物にする
            clothes.Dirty = true;
            DirtyLaundry.Add(clothes);
        }

        // 回数券を買う
        public void BuyCouponTicket()
        {
            // お金は払ってないけれど、省略しているだけ
            CouponTicket.Enqueue(new Coupon());
        }

        // クリーニング店に行く
        public void GoCleaners()
        {
            // 行きつけのクリーニング店.洗濯する(汚れた洗濯物,回数券);
            List<Clothes> clothes = RegularCleaners.Wash(DirtyLaundry, CouponTicket.Dequeue());
            // 仕上り品としてしまう
            CleanLaundry.AddRange(clothes); 
        }

    }
}

Cleaners.csは、「クリーニング店」クラスです。
洗濯する関数だけがありますので、これがシーケンス図内に描かれている部分です。

Cleaners.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cleaners
{
    // クリーニング店
    class Cleaners
    {
        // 洗濯する
        public List<Clothes> Wash(List<Clothes> clothes,Coupon coupon)
        {
            // 回数券クーポンを破棄し
            // (略)

            // 洗濯する
            foreach(Clothes oneClothes in clothes)
            {
                oneClothes.Dirty = false;
            }

            // 返却する
            return clothes;
        }
    }
}

分析モデルとコードを見て

クラス図、シーケンス図、コードを見て、
分析モデルで特定したクラスが、そのままモジュール分割に利用されているのが分かりますよね。
つまり、逆に言えば、モジュールがポンチ絵的な構造をしている、とも言えます。
ポンチ絵的な構造だったら、人間にとって、より分かりやすいですよね。

より素直なコードに見えると思うのです。

これが、オブジェクト指向分析が、モジュール分割に有効な手段の一つだということです。
もしよかったら、参考にしてください。