「#デザインパターン」タグアーカイブ

【デザインパターン】Adapterパターン

Adapterパターンのコード例です。

Adapterには継承を使ったパターンと委譲を使ったパターンがあります。

まずは継承を使用したパターン。

package org.example.adapter;

public class Adaptee {
    public void methodA()
    {

    }

    public void methodB()
    {

    }
}
package org.example.adapter;

public interface Target {
    public void targetMethod1();
    public void targetMethod2();
}
package org.example.adapter;

public class Adapter extends Adaptee implements Target{
    public void targetMethod1() {
        methodA();
    }

    public void targetMethod2() {
        methodB();
    }
}
package org.example.adapter;

public class Main {
    public static void main(String[] args)
    {
        Adaptee adaptee = new Adaptee();
        adaptee.methodA();
        adaptee.methodB();

        Adapter adapter = new Adapter();
        adapter.targetMethod1();
        adapter.targetMethod2();
    }
}

そして、委譲を使用したパターン。

package org.example.adapter;

public class Adapter implements Target{
    Adaptee adaptee;

    public Adapter()
    {
        adaptee = new Adaptee();
    }

    public void targetMethod1() {
        adaptee.methodA();
    }

    public void targetMethod2() {
        adaptee.methodB();
    }
}

このパターンは元々存在していたクラスAdapteeを使用したいけど、インターフェースが合わない、と言う場合、新しいクラスAdapterを作成して使用できるようにした、というパターンです。

継承と委譲がありますが、自分としては委譲の方がしっくりきます。

【デザインパターン】Singletonパターン

Singletonパターンのコード例です。

package org.example.singleton;

public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {

    }

    public static Singleton getInstance() {
        return singleton;
    }

    public void method1() {

    }
}
package org.example.singleton;

public class Main {
    public static void main(String[] args) {
        Singleton obj = Singleton.getInstance();
        obj.method1();
    }
}

Singletonはプログラム上にインスタンスが一つしか存在しない場合に使用されます。

インスタンスの取得はgetInstance()で取得して使用します。

このインスタンスは常に同じもので、一つのインスタンスをみんなで使い回すというイメージですね。

よく使われるパターンです。

【デザインパターン】Prototypeパターン

Prototypeパターンのコート例です。

package org.example.prototype;

import java.io.Closeable;

public interface Prototype extends Cloneable {
    public void method1();
    public void method2();
    public Prototype createClone();
}
package org.example.prototype;

import java.io.IOException;

public class ConcretePrototype implements Prototype {
    public ConcretePrototype() {
        super();
    }

    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }

    @Override
    public Prototype createClone() {
        Prototype prototype = null;

        try {
            prototype = (Prototype)clone();
        }catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return prototype;
    }
}
package org.example.prototype;

public class Main {
    public static void main(String[] args){
        Prototype PrototypeObject = new ConcretePrototype();
        Prototype cloneObject = PrototypeObject.createClone();
        cloneObject.method1();
        cloneObject.method2();
    }
}

Prototypeインターフェースを実装したConcretePrototypeを作成し、以後、createClone()メソッドを使用して複製したものを使用する、という使い方をします。

Cloneableを実装しないとClone()実行時にCloneNotSupportedExceptionが発生するみたいです。

これ、Java以外にもC#とかにも無いっすかね?

※C#ではICloneableを実装すると使えるみたいです。

あと、Cloneは参照型のメンバーがいた場合、複製したObjectも複製前と同じ参照先を参照するらしいです。

完全に複製するには、CloneをOverrideして、参照型のメンバーをさらにCloneする、というやり方が必要になるようです。

Cloneを使用する場合はその当たり気をつけないといけないですね。

【デザインパターン】AbstructFACTORYパターン

AbstructFactoryパターンのコード例です。

package org.example.abstruct.factory.factory;

public abstract class AbstructProduct1 {
    public abstract void method1();
}
package org.example.abstruct.factory.factory;

public abstract class AbstructProduct2 {
    public abstract void method2();
}
package org.example.abstruct.factory.factory;

public abstract class AbstructFactory {
    public static AbstructFactory getFactory(String className)
    {
        AbstructFactory factory = null;
        try {
            factory = (AbstructFactory)Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factory;
    }

    public abstract AbstructProduct1 createAbstructProduct1();
    public abstract AbstructProduct2 createAbstructProduct2();
}
package org.example.abstruct.factory.concrete;

import org.example.abstruct.factory.factory.AbstructProduct1;

public class concreteAbstructProduct1 extends AbstructProduct1 {
    @Override
    public void method1() {

    }
}
package org.example.abstruct.factory.concrete;

import org.example.abstruct.factory.factory.AbstructProduct2;

public class concreteAbstructProduct2 extends AbstructProduct2 {
    @Override
    public void method2() {

    }
}
package org.example.abstruct.factory.concrete;

import org.example.abstruct.factory.factory.AbstructFactory;
import org.example.abstruct.factory.factory.AbstructProduct1;
import org.example.abstruct.factory.factory.AbstructProduct2;

public class concreteAbstructFactory extends AbstructFactory {
    @Override
    public AbstructProduct1 createAbstructProduct1() {
        return new concreteAbstructProduct1();
    }

    @Override
    public AbstructProduct2 createAbstructProduct2() {
        return new concreteAbstructProduct2();
    }
}

Factoryパターンが1Productを作成していたのに対して、AbstructFactoryパターンは複数Productを作成できるようにしたパターンです。

factory作成時にクラス名の文字列からインスタンスを作る、と本に書いてありました。

このやり方はいろいろ応用できるかも。

ちなみに、(AbstructFactory)Class.forName(className).newInstance();と書くのは非推奨となっています。

問題点は、Productを追加した場合、すでに作成している全てのconcreteProductに実装が必要と言うことですね。