Как постараться не называть методы Viritual от основного конструктора

Если Вы надеетесь использовать мощные, высокоуровневые инструменты вместо того, чтобы создать все сами, проходя проекты и чтения для , этот курс является довольно хорошим вариантом. Это - курс языков автором механизма синтаксического анализатора Java ANTLR. Можно получить книгу для курса как PDF от Прагматически настроенные Программисты .

курс пробегается через стандартный материал компилятора компилятора, который Вы видели бы в другом месте: парсинг, типы и проверка типа, полиморфизм, таблицы символов и генерация кода. В значительной степени единственной вещью, которая не покрыта, является оптимизация. Заключительный проект является программой что компиляции подмножество C. Поскольку Вы используете инструменты как ANTLR и LLVM, выполнимо записать весь компилятор в единственный день (у меня есть доказательство существования этого, хотя я действительно имею в виду ~24 часа). Это тяжело на практической разработке с помощью современных инструментов, немного легче на теории.

LLVM, между прочим, является просто фантастическим. Много ситуаций, где Вы могли бы обычно компилировать вниз в блок, Вы будете очень более обеспеченной компиляцией в Промежуточное Представление LLVM вместо этого. Это является высокоуровневым, кросс-платформенным, и LLVM довольно хорош в генерации оптимизированного блока от него.

9
задан WCWedin 20 July 2009 в 19:04
поделиться

8 ответов

Это слишком много, чтобы поместить его в конструктор любого класса, не говоря уже о базовом классе. Я предлагаю вам выделить это в отдельный метод Initialize .

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

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

] В качестве примера:

public abstract class Widget
{
    protected abstract void InitializeStep1();
    protected abstract void InitializeStep2();
    protected abstract void InitializeStep3();

    protected internal void Initialize()
    {
        InitializeStep1();
        InitializeStep2();
        InitializeStep3();
    }

    protected Widget() { }
}

public static class WidgetFactory
{
    public static CreateWidget<T>() where T : Widget, new()
    {
        T newWidget = new T();
        newWidget.Initialize();
        return newWidget;
    }
}

// consumer code...
var someWidget = WidgetFactory.CreateWidget<DerivedWidget>();

Этот заводской код можно значительно улучшить - особенно если вы хотите использовать контейнер IoC для выполнения этой обязанности ...

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

Не всегда возможно запретить пользователям ваших классов стрелять себе в ногу - но,вы можете предоставить инфраструктуру, которая поможет потребителям правильно использовать ваш код, когда они ознакомятся с дизайном.

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

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

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

На первый взгляд, я бы предложил перенести такую ​​логику в методы, основанные на этой инициализации. Что-то вроде

public class Base
{
   private void Initialize()
   {
      // do whatever necessary to initialize
   }

   public void UseMe()
   {
      if (!_initialized) Initialize();
      // do work
   }
}
1
ответ дан 4 December 2019 в 11:43
поделиться

Поскольку шаг 1 «захватывает файл», было бы неплохо иметь Initialize (IBaseFile) и пропустить шаг 1. Таким образом, потребитель может получить файл, как ему заблагорассудится - поскольку это абстрактный в любом случае. Вы по-прежнему можете предложить «StepOneGetFile ()» в качестве абстрактного, возвращающего файл, чтобы они могли реализовать его таким образом, если захотят.

DerivedClass foo = DerivedClass();
foo.Initialize(StepOneGetFile('filepath'));
foo.DoWork();
1
ответ дан 4 December 2019 в 11:43
поделиться

Изменить: Я почему-то ответил на это за C ++. Извините. Для C # я рекомендую не использовать метод Create () - используйте конструктор и убедитесь, что объекты остаются в допустимом состоянии с самого начала. C # разрешает виртуальные вызовы из конструктора, и их можно использовать, если вы тщательно документируете их ожидаемую функцию, а также предварительные и последующие условия. Я сделал вывод о C ++ в первый раз, потому что он не разрешает виртуальные вызовы из конструктора.

Сделайте отдельные функции инициализации закрытыми . Может быть как частным , так и виртуальным . Затем предложите общедоступную невиртуальную функцию Initialize () , которая вызывает их в правильном порядке.

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

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

abstract class Base
{
    private bool _initialized;

    protected abstract void InitilaizationStep1();
    private void InitilaizationStep2() { return; }
    protected abstract void InitilaizationStep3();

    protected Initialize()
    {
        // it is safe to call virtual methods here
        InitilaizationStep1();
        InitilaizationStep2();
        InitilaizationStep3();

        // mark the object as initialized correctly
        _initialized = true;
    }

    public void DoActualWork()
    {
        if (!_initialized) Initialize();
        Console.WriteLine("We are certainly initialized now");
    }
}
1
ответ дан 4 December 2019 в 11:43
поделиться

Я бы не стал этого делать. Я обычно считаю, что выполнение любой «реальной» работы в конструкторе в конечном итоге будет плохой идеей.

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

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

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