プロが教える店舗&オフィスのセキュリティ対策術

こんにちは、
デザインパターンを勉強しており、クラスにファクトリーパターンあるいは、アブストラクトファクトリーパターンを適用したいと思っています。

ConfigDataというクラスがあり、この中には、spec1, spec2, spec3, DateFile1, DateFile2というクラスを持っています。 それぞれ、もとはファイル形式で、このConfigDataクラスで、newをして、パスを渡して、読み込んで、オブジェクトとして保持しています。

そこで、質問なのですが、このようなクラスにファクトリークラスを適用する場合、どうするのがいいのでしょうか?現在は下記のように少ししてみました。

public class ConfigData
{
Spec1 spec1;
Spec2 spec2;
Spec3 spec3;
DateFile1 df1;
DateFile2 df2;

public void importSpec(){
SpecFactotry[] factory = new SpecFactpry[3];
factory[0] = new Spec1Factory();
factory[1] = new Spec2Factory();
factory[2] = new Spec3Factory();

spec1 = (Spec1) factory[0].create(path);
spec2 = (Spec2) factory[1].create(path);
spec3 = (Spec3) factory[2].create(path);
}
}

もともとは、importSpecのところで、ただnewをそれぞれしていました。
このような場合、ファクトリークラスを適用する必要はないのでしょうか?

A 回答 (2件)

>インターフェースにして、外部からパス名をもらったほうがいいのでしょうか。


大事なのは利用側が具象型(Spec1,2,3)ではなく、共通型(Spec)で扱えるということなので、抽象クラスでも問題ありません。

ただ、Javaでは多重継承ができないので私は以下の点に気を付けています。

1.「継承」は基本的に is-a の関係とする。「インタフェース」は特定の機能を付加するもの。
例えばゲームプログラミングなどであれば、Character(親)←Player(子)/Enemy(子)のように、キャラクター=プレイヤー、キャラクター=敵のような関係であれば「継承」を利用します。
ただ、「移動可能」「攻撃可能」「魔法可能」のような「機能」を付加する場合は、「Movable」「Attackable」「Magicable」など「* + able」の命名などで「インタフェース」を利用しています。

2.ただし、インタフェースには処理が記述できない(Java7までは)ので、上記のようなインタフェースを実装した別の「具象クラスX」を用意し、それを「委譲(has-a)」という形でフィールドに保持し、共通処理はその「具象クラスX」にまかせます。
その際、保持しているクラス自身も上記インタフェースを実装しておきます。(デザインパターンで言うと、Compositeパターンになるでしょうか。委譲を利用したAdapterパターンでも良いと思います)

(参考) (h)ttp://www.techscore.com/tech/DesignPattern/Composite.html/
(参考) (h)ttp://www.techscore.com/tech/DesignPattern/Adapter/Adapter2.html/
    • good
    • 0

>このような場合、ファクトリークラスを適用する必要はないのでしょうか?


システムによりけりですが、基本的にはシステムを疎結合に保つことで
拡張性や保守性が上がるので、意識はすると良いかと思います。

最近はDIコンテナが変わりにインスタンス生成してくれたりするので
あまりファクトリーメソッドを使ったことがないのですが、
適用したら下記のようになりますかね?
(間違っていたらどなかたご指摘お願いします)
※DataFileとSpecの関連が分からなかったので、DataFileは無視してます。

【ファクトリーメソッドだけ適用】
まずは生成対象オブジェクト(Spec1,2,3など)を疎に扱うために
それぞれ同一のインタフェースを実装する必要があるかと思います。

public interface Spec {
// Spec に関する公開処理
}

public class Spec1 implements Spec {...
public class Spec2 implements Spec {...
public class Spec3 implements Spec {...

これらを利用する側は、Spec1,2,3などの具体的なクラスは意識せず
Specインタフェースのみ意識するように作ります。

そのため、ファクトリーメソッドでSpec型で返すようにしておきます。

Spec s = createSpec(); // 1, 2, 3 のいずれかが返る。
s.process(); // 1,2,3を意識させず、疎に扱う。インスタンスの動作にまかせる。

createSpec() メソッドは、何らかの条件で1,2,3のいずれかの
インスタンスを返したりするようにしておく。
(この createSpec() がファクトリーメソッド)

こうしておくと利用側は、例えば Spec4,5 が増えても修正不要。
修正が必要なのはファクトリーメソッドのみとなります。
(ご質問の例では、Spec1,2のキャストを行っているので、クラスが増えると対応が必要)


【アブストラクトファクトリーも適用】
上記に加えて、ファクトリー自身も抽象化します。

public interface SpecFactory {...

public class Spec1Factory implements SpecFactory {...
public class Spec2Factory implements SpecFactory {...
public class Spec3Factory implements SpecFactory {...

Factory(工場)自身も抽象化し、それぞれSpec1やSpec2だけに関連した処理をまとめます。
利用する側は、SpecFactory インタフェースとして扱うことで、
それぞれに特化した処理が施された結果で受け取ることができます。

ご質問の例では、Spec のみ扱っているのでファクトリーメソッド適用の段階で止めても良い気がしますが、例えば「Spec1 と DataFile1」、「Spec2 と DataFile2」がそれぞれ紐付くのであれば、適したファクトリーにその組み合わせでの処理を記述しておけば、
利用する側は「Spec1 と DataFile2」などの組み合わせの間違いを防ぐことができます。

この回答への補足

DateFile1とSpecは特に関係はありません。実はそれぞれ、エクセルファイルだったり、テキストだったりして、それを読み込んでいます。spec1から3までは、エクセルファイルで若干、書かれている内容が違ったりしています。データファイルはテキストファイル(ini)を読み込んでデータを保持しています。

私は、Specを抽象クラスにして、1、2、3をその子にしました。というのはSPECクラスにおいて、読込先のファイルパスを保持していたり、ファイル名の部分は共通でもっておくべくかなと思ったので。インターフェースにして、外部からパス名をもらったほうがいいのでしょうか。

補足日時:2014/03/06 17:36
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!