Каково различие между абстрактным классом и классом только с защищенными конструкторами? (.NET)

Каково все различие между абстрактным классом и классом только с защищенным конструктором (конструкторами)? Они, кажется, довольно подобны мне, в котором Вы не можете инстанцировать ни одного.

Править:

Как Вы создали бы экземпляр в производном классе с базовым классом с защищенным конструктором? Например:

public class ProtectedConstructor
{
    protected ProtectedConstructor()
    {

    }

    public static ProtectedConstructor GetInstance()
    {
        return new ProtectedConstructor(); // this is fine
    }
}

public class DerivedClass : ProtectedConstructor
{

    public void createInstance()
    {
        ProtectedConstructor p = new ProtectedConstructor(); // doesn't compile
    }

    public static ProtectedConstructor getInstance()
    {
        return new ProtectedConstructor(); // doesn't compile

    }
}
9
задан 3 revs 5 February 2010 в 20:57
поделиться

9 ответов

Вы можете создать экземпляр класса с защищенными конструкторами внутри самого класса - в статическом конструкторе или статическом методе. Это можно использовать для реализации синглтона или объекта фабричного типа.

Абстрактный класс не может быть создан вообще - намерение состоит в том, чтобы один или несколько дочерних классов завершили реализацию, и эти классы будут созданы

Изменить:

если вы вызовете ProtectedConstructor.GetInstance ( ); вместо new ProtectedConstructor (); работает. Может, так нельзя называть защищенные конструкторы? Но защищенные методы, безусловно, могут.

Вот интересная статья по теме.

12
ответ дан 4 December 2019 в 11:04
поделиться

Абстрактный класс может иметь абстрактные методы; методы, которые состоят только из сигнатуры метода, но не тела, которые дочерние классы должны реализовать.

Серьезно, никто еще не упомянул об этом?

1
ответ дан 4 December 2019 в 11:04
поделиться

Ваш пример ошибочен, потому что в случае getInstance вы создаете класс ProtectedConstructor и ожидаете его преобразования как DerivedClass. Вместо этого вам нужна чуть более полная реализация, в которой производный класс имеет конструктор:

public class ProtectedConstructor
{
    protected ProtectedConstructor(string arg)
    {
        // do something with arg
    }

    public static ProtectedConstructor GetInstance()
    {
        return new ProtectedConstructor("test"); 
    }
} 

public class DerivedClass : ProtectedConstructor
{
    protected DerivedClass(string arg) : base(arg)
    {
    }

    public void createInstance()
    {
        DerivedClass p = new DerivedClass("test"); 
    }

    public static DerivedClass getInstance()
    {
        return new DerivedClass("test"); 
    }
}

Несмотря на то, что основным отличием использования абстрактных классов является определение абстрактных методов, которые подклассы должны реализовать, но вы не хотите предоставлять реализацию по умолчанию. Например, предположим, что у вас есть какой-то класс Thread, у которого есть метод Run. Вы хотите убедиться, что каждый вызов Run сначала настраивает некоторое ведение журнала, затем выполняет реальную работу потока, а затем прекращает регистрацию. Вы можете написать абстрактный класс Thread следующим образом:

public abstract Thread
{
    protected Thread()
    {
    }

    public void Run()
    {
        LogStart();
        DoRun();
        LogEnd();
    }

    protected abstract DoRun();

    private void LogStart()
    {
         Console.Write("Starting Thread Run");
    }

    private void LogEnd()
    {
         Console.Write("Ending Thread Run");
    }
}


public class HelloWorldThread : Thread
{
    public HelloWorldThread()
    {
    }

    protected override DoRun()
    {
        Console.Write("Hello World");
    }
}
1
ответ дан 4 December 2019 в 11:04
поделиться

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

Чтобы другие люди не могли вносить подобные изменения, вы можете комментировать свой код. Или, как говорили другие, используйте слово «абстрактное», чтобы явно задокументировать свои намерения.

1
ответ дан 4 December 2019 в 11:04
поделиться

Если вы намерены разрешить только статическое использование класса (т.е. не использовать его как чистый базовый класс), тогда вам следует использовать вместо этого ключевое слово static ; CLR предотвратит создание экземпляров класса с помощью любого метода, включая Reflection (AFAIK).

0
ответ дан 4 December 2019 в 11:04
поделиться

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

Обычным примером этого может быть что-то вроде одноэлементного шаблона: http://en.wikipedia.org/wiki/Singleton_pattern

0
ответ дан 4 December 2019 в 11:04
поделиться

В большинстве случаев практическая разница невелика, так как и то, и другое может быть сгенерировано только через подкласс.

Однако, маркировка класса абстрактная имеет два преимущества:

  1. С помощью защищенных конструкторов все еще можно создать экземпляр класса двумя способами. Вы можете использовать Activator.CreateInstance с BindingFlags.NonPublic, или вы можете использовать заводской метод, определенный в классе (или подклассе) для создания экземпляра класса. Класс, помеченный абстрактным, однако, не может быть создан.

  2. Вы делаете свои намерения более понятными, пометив класс абстрактным . Лично я нахожу это наиболее веской причиной.

3
ответ дан 4 December 2019 в 11:04
поделиться

С внешней стороны, с точки зрения черного ящика, да, они схожи в том, что вы не можете конкретизировать ни то, ни другое. Однако, вы можете никогда не инстанцировать абстрактный класс, где вы можете построить класс только с защищенными конструкторами изнутри самого класса или от наследника.

1
ответ дан 4 December 2019 в 11:04
поделиться

если вы наследуете абстрактный класс от другого абстрактного класса, вам не нужно удовлетворять абстрактным методам, но вы делаете это с обычным классом с защищаемыми докторами. Examples


public abstract class Parent
{
  protected abstract void AMethod();
}

public abstract class Child: Parent
{
  // does not implement AMethod, and that's ok
}

public class Child2: Parent
{
  // does not implement AMethod, and that will cause a compile error
}

0
ответ дан 4 December 2019 в 11:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: