「デザインパターン」カテゴリーアーカイブ

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

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

package org.example.builder;

public abstract class Builder {
    public abstract void buildPart1(Product product);
    public abstract void buildPart2(Product product);
}
package org.example.builder;

public class ConcreteBuilder extends Builder {
    private Product product;

    @Override
    public void buildPart1(Product product) {

    }

    @Override
    public void buildPart2(Product product) {

    }

    public Product getResult(){
        return product;
    }
}
package org.example.builder;

public class Director {
    private Builder builder;
    public Director(Builder builder)
    {
        super();
        this.builder = builder;
    }

    public void construct(Product product)
    {
        builder.buildPart1(product);
        builder.buildPart2(product);;
    }
}
package org.example.builder;

public class Main {
    public static void main(String[] args)
    {
        Product product = new Product();

        ConcreteBuilder concreteBuilder = new ConcreteBuilder();
        Director director = new Director(concreteBuilder);
        director.construct(product);
        Product result = concreteBuilder.getResult();
    }
}

処理に必要なデータを段階的に渡していき、最後に処理結果を取得するパターンです。

LaravelのSQLビルダがそれに近いですね。

Builderインターフェースを定義し、それをConcreteBuilderとして実装します。

DirectorのコンストラクタにConcreteBuilderを渡し、以後、Directorのconstructメソッドで必要なパラメータをBuilderに渡します。

結果はgetResultで取得します。

【デザインパターン】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に実装が必要と言うことですね。

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

なんでデザインパターンの話になるとJavaなのかね?

まぁ、概念が解れば他の言語にでも応用は可能だけど。

さくっとサンプルコードを書いてみました。

package org.example.factory.creator;

public abstract class Product {
    public abstract void methodA();
    public abstract void methodB();
}

package org.example.factory.creator;

public abstract class Creator {
    public final Product create() {
        Product product = factoryMethod();
        return product;
    }

    protected abstract Product factoryMethod();
}

package org.example.factory.concrete;

import org.example.factory.creator.Product;

public class ConcreteProduct extends Product {
    public ConcreteProduct() {
        super();
    }

    public void methodA() {

    }

    public void methodB() {

    }
}

package org.example.factory.concrete;

import org.example.factory.creator.Creator;
import org.example.factory.creator.Product;

public class ConcreteCreator extends Creator {

    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}
package org.example.factory;

import org.example.factory.creator.*;
import org.example.factory.concrete.*;

public class Main {
    public static void main(String[] args) {
        Creator factory = new ConcreteCreator();
        Product object = factory.create();
        object.methodA();
        object.methodB();
    }
}

抽象クラスProductとCreatorを作成します。

Creatorクラスではcreateメソッドを実装していますが、その実態であるfactoryMethod()は抽象メソッドです。

これを使用するにはProductとCreatorを実装したクラスを作成する必要があります。

それがConcreteProductとConcreteCreatorという例で作成しています。

使用する場合は、まずはConcreteCreatorをインスタンス化し、Creator型で保持します。

以後、create()メソッドを使用して、ConcreteProductのインスタンスを作成して使用します。

新しいProductを追加する場合は、同じようにProductとCreatorを実装するクラスを作成し、Creator型で新しいCreatorをインスタンス化して使用すれば対応可能です。

このパターンを使用するメリットとしては、Productを作成する窓口がcreate()メソッドに一本化されます。

Productの初期設定をfactoryMethod()内に実装すれば、Productに対するあれこれ設定をするという余計な手間が省けます。