убедитесь, что объект создан только фабрикой (C #) - PullRequest
6 голосов
/ 08 сентября 2010

Как я могу убедиться, что определенный класс создается только фабрикой, а не вызывая new напрямую?

РЕДАКТИРОВАТЬ: Мне нужна фабрика длябыть отдельным классом (для целей внедрения зависимостей), поэтому я не могу сделать его статическим методом экземпляра класса, и поэтому я не могу сделать новый закрытым.

Ответы [ 8 ]

22 голосов
/ 08 сентября 2010

Если фабрика находится в той же сборке и вам нужна только защита от внешних сборок, создающих экземпляр класса, вы можете сделать конструктор внутренним.Единственный известный мне способ предотвратить это для всех других классов (в том числе в той же сборке) - сделать экземпляр класса вложенным закрытым классом фабрики и предоставить его только как интерфейс.Если класс является собственной фабрикой (метод статической фабрики), вы можете сделать конструктор частным, как уже упоминали другие.

11 голосов
/ 08 сентября 2010

Сделайте его конструкторы частными и предоставьте фабричный метод как статический метод для самого класса.

В большинстве случаев вы можете просто сделать конструкторы внутренними, что позволит вам разбить фабрику на ее собственный класс -Я обнаружил, что часто не стоит пытаться запретить моей собственной команде использовать new для создания экземпляров в сборке класса.

5 голосов
/ 09 сентября 2010

Если по какой-то причине вам нужно, чтобы фабрика и созданный класс находились в отдельных сборках (что означает, что простое использование internal не будет работать), и вы можете быть уверены, что ваша фабрика получит шанс запустить в первую очередь, Вы можете сделать это:

// In factory assembly:

public class Factory
{
    public Factory()
    {
        token = new object();
        MyClass.StoreCreateToken(token);
    }

    public MyClass Create()
    {
        return new MyClass(token);
    }

    private object token;
}

// In other assembly:

public class MyClass
{
    public static void StoreCreateToken(object token)
    {
        if (token != null) throw new InvalidOperationException(
            "Only one factory can create MyClass.");

        this.token = token;
    }

    public MyClass(object token)
    {
        if (this.token != token) throw new InvalidOperationException(
            "Need an appropriate token to create MyClass.");
    }

    private static object token;
}

Да, это громоздко и неловко. Но могут быть странные ситуации, когда это действительно хорошее решение.

5 голосов
/ 08 сентября 2010

Сделайте конструктор внутренним и разместите фабрику в той же сборке.

public MyClass
{
    internal MyClass()
    {
    }
}

в той же сборке

public MyClassGenerator
{
    public static CreateMyClass()
    {
        return new MyClass();
    }
}

Если фабрика не может быть в той же сборке или этойметод не работает для вас, посмотрите ответ Дэна

2 голосов
/ 12 июня 2017

Вы можете создавать ваши конкретные классы как вложенные частные классы с открытыми конструкторами внутри вашего фабричного класса - таким образом ваша фабрика может создавать их, другие даже не видят их.В любом случае вы возвращаете с фабрики некоторый интерфейсный / абстрактный класс, а не конкретный тип.Конечно, вы не сможете преобразовать свой тип возвращаемого значения в конкретный тип где-нибудь в клиентском коде, но сначала это признак плохого дизайна, во-вторых, вы всегда можете обойти его с помощью более конкретного интерфейсного / абстрактного класса, который наследует ваш вложенный закрытый класс.

Вы можете обратиться к ответу Эрика Липперта здесь (для аналогичной проблемы): Зачем мне когда-либо нужно использовать вложенные классы C #

1 голос
/ 08 сентября 2010

Многие люди упоминали об использовании internal, но вы также можете защитить свои конструкторы и получить класс, в котором есть только статический метод фабрики.Это не мешает другим делать то же самое, но довольно неплохо справляется с ограничением прямого доступа к вашим конструкторам.

1 голос
/ 08 сентября 2010

Он всегда будет создаваться путем вызова new где-то , но если вы хотите, чтобы это происходило только в вашем классе фабрики, вы можете установить для всех конструкторов значение Internal (или Private) и использовать фабрику Public Static.метод в том же классе).

0 голосов
/ 08 сентября 2010

Мне не нравится иметь фабрику на самом типе, особенно если это объект домена.Имейте это внутренний , если у вас есть отдельный класс как фабрика (который, я думаю, вы должны).Используйте атрибут InternalVisible, если фабрика находится в другой сборке.

...