LoginSignup
9
7

More than 5 years have passed since last update.

StateパターンとStrategyパターンを勉強しました

Posted at

みなさん。今年最後の日です。自分のブログで"年内にもう一度Qiitaに投稿する"と一ヶ月ほど前に宣言し、なんと年内の本当の最後の最後にようやく投稿するということになりました:sweat_smile:

普段はC#をメインに勉強しているのですが、デザインパターンの本は大体JAVAだったのでJAVAで頑張って書いてみました。

未熟者の私は今年になってようやく"デザインパターン"というものを知りました。

デザインパターンは、まさにベジータのビッグバンアタックのような衝撃を私に与えました。
StateとStrategyの違いがいまいちよくわからなかったので自分なりにまとめます。違っていたらごめんなさい。

Stateは状態で、外部的というか内部的な動きをします
Strategyは戦略で、どの戦略を取るかというのを外部的に決めている

このように感じました。

というわけで今回は進藤京介という人間でこの2つのパターンを買いてみました。
少し長くなるかもしれませんが、ご了承ください。

まずプログラムについてです。

進藤京介という人間が一人だけ存在しています。
進藤京介は普通に仕事するか、一生懸命仕事するかを選びます。(Strategy)
そして仕事によって経験値を得て、その経験値によって進藤京介はランクが上がっていきます。(State)

というくだらないプログラムです。

まずは実行するMainから書きます。

Main.java

package Kyosuke;

public class Main {

    public static void main(String[] args) {
        Human kyosuke = new Kyosuke();
        //仕事して経験値を1ゲットする
        kyosuke.DoWork();
        //一生懸命仕事して経験値を3ゲットする
        kyosuke.ChangeWorkStyle(new HardWork());
        kyosuke.DoWork();
        //やっぱり普通に仕事をします
        kyosuke.ChangeWorkStyle(new NomalWork());
        kyosuke.DoWork();
        kyosuke.DoWork();
        kyosuke.DoWork();
        //今日から本気出すわw
        kyosuke.ChangeWorkStyle(new HardWork());
        kyosuke.DoWork();
        kyosuke.DoWork();
        kyosuke.DoWork();
        kyosuke.DoWork();
        kyosuke.DoWork();
        kyosuke.DoWork();

    }
}



ランクがBランクになりました
普通に仕事したので経験値を1獲得しました
一生懸命仕事をしたので経験値を3獲得しました
普通に仕事したので経験値を1獲得しました
普通に仕事したので経験値を1獲得しました
普通に仕事したので経験値を1獲得しました
一生懸命仕事をしたので経験値を3獲得しました
ランクがAランクになりました
一生懸命仕事をしたので経験値を3獲得しました
一生懸命仕事をしたので経験値を3獲得しました
一生懸命仕事をしたので経験値を3獲得しました
一生懸命仕事をしたので経験値を3獲得しました
カンストしましたw
一生懸命仕事をしたので経験値を3獲得しました
カンストしましたw

最初のランクはBランクです。そして仕事も普通に仕事をします。
途中で一生懸命仕事をしたりしてランクが上がっていき、最終的にはカンストします

では進藤京介という人間についてみていきます。

Human.java

package Kyosuke;

interface Human {
    void DoWork();
    void SetRank(Rank newRank);
    void ChangeWorkStyle(Work style);
    int GetExperiencepoint();
}


Kyosuke.java

package Kyosuke;

public class Kyosuke implements Human{
    private Rank rank;
    private Work work;
    private int experiencepoint;

    public Kyosuke() {
        this.rank = new BRank(this);
        this.work = new NomalWork();
        //最初は経験値1
        this.experiencepoint = 1;
    }

    @Override
    public void DoWork() {
        int point = work.DoWork();
        this.experiencepoint += point;
        //ここでRank確認する
        rank.CheckNextRank();
    }

    @Override
    public void SetRank(Rank newRank) {
        this.rank = newRank;
    }

    @Override
    public void ChangeWorkStyle(Work style) {
        this.work = style;
    }

    @Override
    public int GetExperiencepoint() {
        return this.experiencepoint;
    }
}


現在のランクを表すRankと、仕事を表す(意味不明)Workと、経験値experiencepointを持っています。

コンストラクタでこれら全てを初期化します。
実際に仕事する動作、ランクを変える動作、仕事スタイルを変える動作、経験値を返すもの
これらをオーバーライドします。

では、仕事スタイルについて書いていきます。

Work.java
package Kyosuke;

public abstract class Work {
    public abstract int DoWork();
}

NomalWork.java
package Kyosuke;
public class NomalWork extends Work{
    private final int experiencePoint =1;
    @Override
    public int DoWork() {
        System.out.println("普通に仕事したので経験値を1獲得しました");
        return experiencePoint;
    }
}

HardWork.java
package Kyosuke;
public class HardWork extends Work{
    private final int experiencePoint = 3;
    @Override
    public int DoWork() {
        System.out.println("一生懸命仕事をしたので経験値を3獲得しました");
        return experiencePoint;
    }
}

まぁ単純に仕事をすれば経験値を返してくれます。
このパターンを使わないと、if文やらswitch文やらが必要になってしまいますが
具体的な処理はサブクラスが実装することで簡単に切り替えを行えます。

Rank.java
package Kyosuke;

public abstract class Rank {
    protected int experinencepoint;
    protected int nextLeve;
    protected Human human;

    public Rank(Human human){
        this.human = human;
    }

    protected void SetExperinencepoint(){
        this.experinencepoint =human.GetExperiencepoint();
    }

    protected abstract void CheckNextRank();
}

そしてRankです。これがStateになります。進藤京介の経験値をランクという状態で表現します。コンストラクタでは進藤京介を受け取ります。

BRank.java
package Kyosuke;

public class BRank extends Rank{
    public BRank(Human human){
        super(human);   
        this.nextLeve = 8;
        System.out.println("ランクがBランクになりました");
    }
    @Override
    protected void CheckNextRank() {
        //まずは経験値を調べる
        SetExperinencepoint();
        //経験値が次のレベルを越えればレベルアップ
        if (experinencepoint > nextLeve){
            human.SetRank(new ARank(this.human));
        }
    }

}

Rankのサブクラスでは必要なメソッドをオーバーライドします。
またコンストラクタでは親クラスのコンストラクタを呼び出して、進藤京介をセットします。
そして次のレベルまでは経験値が8必要ということをnextLeveに設定します(ネクストレベってなんだよ)

ポイントはCheckNextRankメソッドです。
進藤京介の経験値を読み取って、それによって状態を変化させています。
具体的には
SetExperinencepoint();
で経験値を読み取り、コンストラクタで設定した次のレベルの条件を超えていれば、ランクをAランクに上げます。(状態を変化させます)

Mainメソッド側では、この状態の変化には一切関与していません。
全て内部で勝手に動いている状態です。

ARank.java
package Kyosuke;

public class ARank extends Rank{
    public ARank(Human human){
        super(human);
        nextLeve = 20;
        System.out.println("ランクがAランクになりました");
    }

    @Override
    protected void CheckNextRank() {
        //まずは経験値を調べる
        SetExperinencepoint();
        //経験値が次のレベルを越えればレベルアップ
        if (experinencepoint > nextLeve){
            System.out.println("カンストしましたw");
        }
    }

}


そしてARankも同じようにコンストラクタで進藤京介を受け取っています。
処理内容はBRankと同じですね。
もしもカンストせずにBRankに戻すとか、もっと上のレベルに行くとかする場合も、同じように進藤京介を渡してあげればいいですね。

ものすごく簡単にまとめてしまいましたが以上になります。

デザインパターンは魔法のようでした。
もっともっと学ぶべきだと思わせてくれる、そんな先生でもあります。

えー、いきなりですが
来年は無職スタートになります:pensive:

とにかく修行して、プログラミングで食っていけるように頑張ります。

9
7
1

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
9
7