BLOG

2018-11-11

【Javaのお話】デザインパターン編

わっふい!アラサーの縞次郎です。

以前、社内の勉強会資料としてまとめたものをブログ用に再編してご紹介したいと思います。

今回はデザインパターンのお話です。

開発を行っていると少なからず耳にする「デザインパターン」

なんとなーく聞いたことあるけど、実際に深く調べたことがなかったので、一から調査してみました。

前置き

そもそも、デザインパターンってご存知ですか?

歴史的な背景を紐解くと、1990年代に出版された『オブジェクト指向における再利用のためのデザインパターン』といった書籍があります。

この本ではGoF(Gang of Four)のデザインパターンとして23のパターンが紹介されており、プログラマの共通言語的に使われるものなので1度は読んでおくべきかもしれません。

ただし、少し調べてわかったことがあります。

上記の書籍は、現代のプログラミングには当てはまらない部分も多々存在しているようです。

以下、ネットの反応

  •  ◆オブジェクト指向が未成熟な時代に出版されたもの
  •  ◆列挙されたパターンに根拠がない
  •  ◆古典的な知識を今更知っても仕方ない

などといった反応が散見されます。 言われてみれば確かに、なるほどと思ってしまう意見でした。

特に、「オブジェクト言語が未成熟な時代」にまとめられた知識であるため、色々と不自由だったために考案されたものが多くあるようです。

→言語のバージョンが上がったことで、標準機能として搭載されたものもある

私見

個人的な意見というか、考え方ですが。。。 先人達の知恵と工夫の積み重ねによって現在の技術が存在する訳なので

古い知識であろうとも、先人達が残した遺産にあやかれるのであれば

ありがたくあやかっておけばいいじゃない!と思うのです。

今でもレガシーなシステムは確かに存在するので、目にする機会はゼロではないと思われます。

時間とお金に余裕のある人はきちんと、一から勉強をすれば良いと思います。

が、目紛しく移りゆく現代に生きる我々には先人の知恵を一から辿るには時間が圧倒的に足りないのです。(言い訳)

本題

つらつらと述べましたが、言いたいこととしては、美味しいとこだけさらって、 さくっと知識を身に着けたい!!!

GoFのデザインパターン

基本的なことだけご紹介 パターンを大別すると以下の3パターン

  1.  1.オブジェクトの生成に関するパターン
  2.  2.プログラムの構造に関するパターン
  3.  3.オブジェクトの振舞に関するパターン

ということらしい。

デザインパターンのメリット

さて、デザインパターンを利用するメリットを考えてみましょう。

個人的に意味があるなと思うことは、

  •  ■開発スピードが向上する
    •   □情報伝達が容易に
    •   □解析が容易に
  •  ■保守性が向上する
    •   □機能追加・修正が容易に
  •  ■プログラムの構造設計ができる様になる
    •   □アプリケーションの構造設計につながっていく

デザインパターンとは、「よくある問題をうまく解決・対処するための設計」なんて言われています。

再利用性を高くすることで、玄人だけでなく初心者であっても素敵なプログラミングが可能になります。

Javaで使えるデザインパターン

Javaの開発で避けては通れないのが、マルチスレッドプログラミング。

今回はそんなマルチスレッドプログラミングで起こりやすい問題を解決できるかもしれないするデザインパターンをご紹介。

Guarded Suspension / Balking

条件を満たさないときにスレッドを待機させる。または処理を行わない。

マルチスレッドは非同期で動作するため、不用意な状態で処理が実行されることを防げる。

Guarded Suspension / Balkingパターンサンプル

// 状態フラグ
private isBusy = false;

// 実行メソッド
public void execute(){
    synchronized(this){
        if(isBusy){
            wait(); // falseになるまで待機する場合はGuarded Suspensionパターン
            return; // すぐにreturnする場合はBalkingパターン
        }
      	// do something { isBusy = true; }
      	isBusy = false;
    }
}

Woker Thread

ワーカースレッドと呼ばれる専用のスレッドを起動しておき、タスクがあれば順次処理を実行する。

ファイルやQueueの監視に使われる。

Woker Threadパターンサンプル

/** 仕事を与えるクラス */
public class Client extend Thread{
    private Channel channel;
    :
    public void run() {
        while(true){ //永遠に仕事を与え続ける
            Work work = new Work();
            channel.putWork(work); 
        }
    }
}
/** 仕事の管理クラス */
public class Channel {
    private Queue<Work> workQueue = new Queue<>();
    /** 仕事をQueueに保持する */
    public void putWork(Work work) {
        workQueue.add(work);
    }
    /** 仕事をQueueから取得する */
    public Work getWork() {
        return workQueue.poll();
    }
}
/** 仕事の実行クラス */
public class WorkerThread extend Thread {
    private Channel channel;
    :
    public void run() {
        while(true) {                      // 永遠に働き続ける
            Work work = channel.getWork(); // 仕事を取りに行く
            work.execute();                // 仕事の実行
        }
    }
}

Two-Phase Termination

スレッドの処理を、メイン処理と終了処理に分けてスレッドを安全に終了するためのパターン。

スレッド内に終了要求するメソッドを用意し、終了用のフラグの更新と処理割り込みメソッドinterrupt()を呼ぶ。

終了要求を受けたスレッドは安全に終了できるタイミングで終了処理を開始する。

Two-Phase Terminationパターンサンプル

// 終了要求が出されたらtrue
private volatile boolean shutdownRequested = false;
// 終了要求
public void shutdownRequest() {
    shutdownRequested = true;
    interrupt();
}
// 動作
public final void run() {
    try {
        while (!shutdownRequested) {
            // doWork();
            if(終了条件) {
                shutdownRequest();
            }
        }
    } catch (InterruptedException e) {
    } finally {
        // doShutdown();
    }
}

まとめ

デザインパターンについてのお話でした。 デザインパターンの知識的な部分〜技術的な部分をほんの少しだけ紹介しました。

デザインパターンはやりたいことに対してテンプレート的な考えで使用できるため、一から自分で考える必要がなくなり、工数の圧縮や削減に役立つ可能性があるので、ぜひ身に付けておきたい知識だと思いました。

ただし、注意が必要だと思われるのが、デザインパターンが「絶対的な解法」ではなく、あくまでも解決の一手法だということです。思考停止気味にデザインパターンを用いることで、却ってイケテナイ設計になったり、余計な工数を費やすことになることもありえます。

選択肢の一つとして選べる、考え方のベースにして応用できることが大事です。

クラス設計〜製造工程において、力を発揮するであろうデザインパターンですが、1つ知っていれば良いというものではないので、色々な引き出しを持つことが大切です。


The following two tabs change content below.

縞次郎

Java、Android中心に開発やってます。 サーバサイドの開発が多いですが、フロントもそこそこやれると信じているアラサーSE。

最新記事 by 縞次郎 (全て見る)