4

私はよくクラスファクトリパターンを使用します。このパターンでは、クラスにプライベートコンストラクタと静的メソッドを使用してクラスを作成します。これにより、何らかの理由でクラスを構築できず、nullが返される状況が可能になります。これは非常に便利です。

これを、条件に応じて派生クラスの階層から特定のクラスを作成するファクトリメソッドに拡張できるようにしたいと思います。ただし、派生クラスのコンストラクターを非表示にして、ファクトリメソッドの使用を強制する方法がわかりません。ファクトリメソッドが基本クラスにある場合、派生クラスのプライベートコンストラクタにアクセスできなくなります。必要な型を事前に知っておく必要があるため、すべての派生クラスにファクトリメソッドを配置しても機能しません。ネストされたクラスは、クラスがネストされたクラスのプライベートメンバーにアクセスできる場合の方法かもしれませんが、残念ながら、ネストされたクラスはそれを含むクラスのプライベートメンバーにアクセスできるようですが、その逆はありません。

誰かがこれを行う方法を知っていますか?

4

4 に答える 4

4

いくつかの可能性がありますが、そのうちの 2 つは次のとおりです。

  1. これらすべてのクラスを 1 つのプロジェクトに入れ、コンストラクターを作成しinternalます。他のプロジェクトはこれらのコンストラクターを呼び出すことはできませんが、そのプロジェクト内のコードはできます。
  2. これらのクラスのコンストラクターをprotected( の代わりにprivate) 作成し、ファクトリ メソッドを含むクラスにプライベート派生クラスを作成します。そのプライベート クラスのインスタンスを作成し、それを返します。

2 番目のオプションの例:

public static class AnimalFactory
{
    public static Animal Create(int parameter)
    {
        switch(parameter)
        {
            case 0:
                return new DogProxy();
            case 1:
                return new CatProxy();
            default:
                throw new ArgumentOutOfRangeException("parameter");
        }
    }

    private class DogProxy : Dog { }

    private class CatProxy : Cat { }
}

public abstract class Animal { }

public class Dog : Animal
{
    protected Dog() { }
}

public class Cat : Animal
{
    protected Cat() { }
}
于 2013-02-20T10:23:16.920 に答える
1

ダニエルが回答を投稿したときに取り組んでいたサンプル コードを次に示します。彼が提案したことをやっているようです:

public static class BaseFactory
{
    public static Base Create(bool condition)
    {
        if (condition)
        {
            return Derived1.Create(1, "TEST");
        }
        else
        {
            return Derived2.Create(1, DateTime.Now);
        }
    }
}

public class Base
{
    protected Base(int value)
    {
    }

    protected static Base Create(int value)
    {
        return new Base(value);
    }
}

public sealed class Derived1: Base
{
    private Derived1(int value, string text): base(value)
    {
    }

    internal static Derived1 Create(int value, string text)
    {
        return new Derived1(value, text);
    }
}

public sealed class Derived2: Base
{
    private Derived2(int value, DateTime time): base(value)
    {
    }

    internal static Derived2 Create(int value, DateTime time)
    {
        return new Derived2(value, time);
    }
}

[編集] そして、ダニエルの 2 番目の提案:

public static class BaseFactory
{
    public static Base Create(bool condition)
    {
        if (condition)
        {
            return new Derived1Creator(1, "TEST");
        }
        else
        {
            return new Derived2Creator(1, DateTime.Now);
        }
    }

    private sealed class Derived1Creator: Derived1
    {
        public Derived1Creator(int value, string text): base(value, text)
        {
        }
    }

    private sealed class Derived2Creator: Derived2
    {
        public Derived2Creator(int value, DateTime time): base(value, time)
        {
        }
    }
}

public class Base
{
    protected Base(int value)
    {
    }

    protected static Base Create(int value)
    {
        return new Base(value);
    }
}

public class Derived1: Base
{
    protected Derived1(int value, string text): base(value)
    {
    }

    protected static Derived1 Create(int value, string text)
    {
        return new Derived1(value, text);
    }
}

public class Derived2: Base
{
    protected Derived2(int value, DateTime time): base(value)
    {
    }

    protected static Derived2 Create(int value, DateTime time)
    {
        return new Derived2(value, time);
    }
}

残念ながら、この 2 番目のアプローチは、クラスをシールできないことを意味することに注意してください。

于 2013-02-20T10:24:24.077 に答える
0

基本クラスのコンストラクターで派生型の作成をインターセプトし、StackFramesを使用して呼び出し元がファクトリであることを確認できます。

 protected Class1() //base class ctor
    {
        StackFrame[] stackFrames = new StackTrace().GetFrames(); 
        foreach (var frame in stackFrames)
        {
            //check caller and throw an exception if not satisfied
        }
    }
于 2013-02-20T10:26:02.143 に答える
0

クラス自体の内部でファクトリとしてメソッドを使用するのではなく、記述したロジックに基づいて正しいインスタンスを返す静的クラス (「ファクトリ」) を使用して Factory パターンを実装します。

于 2013-02-20T10:21:26.617 に答える