Как избежать круговой ссылки единицы?

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

Также удостоверяются, что "Символы загрузки лениво" не выбраны в предпочтениях отладки.

(Относится к Xcode 3.1, не уверенному в прошлом/будущих версиях)

16
задан jpfollenius 16 August 2009 в 18:17
поделиться

8 ответов

Измените единицу измерения TChessPiece, чтобы она выглядела следующим образом:

TYPE
  tBaseChessBoard = class;

  TChessPiece = class
    procedure GetMoveTargets (BoardPos : TPoint; Board : TBaseChessBoard; ...    
  ...
  end;    

затем измените модуль, определяющий TChessBoard, чтобы он выглядел следующим образом:

USES
  unit_containing_tBaseChessboard;

TYPE
  TChessBoard = class(tBaseChessBoard)
  private
    FBoard : array [1..8, 1..8] of TChessPiece;
  ...
  end;  

Это позволяет вам передавать конкретные экземпляры в шахматную фигуру, не беспокоясь о круговой ссылке. Поскольку доска использует Tchesspieces как частное лицо, на самом деле она не должна существовать до объявления Tchesspiece, просто как заполнитель. Любые переменные состояния, о которых должен знать tChessPiece, конечно, должны быть помещены в tBaseChessBoard, где они будут доступны обоим.

11
ответ дан 30 November 2019 в 15:28
поделиться

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

Распределенное, два репозитория

Активы в одном репо и код в другом.

Преимущества

  • В контексте веб-разработки вам не нужно клонировать гигантский репозиторий активов если вы не работаете напрямую с графическими файлами. Это возможно, если у вас есть веб-сервер, который обрабатывает ресурсы отдельно от динамического контента (PHP, ASP.NET, RoR и т. Д.) И синхронизируется с репозиторием ресурсов.

Недостатки

  • Инструменты DVCS не отслеживают других репозиториев, кроме их собственного, поэтому нет никакой прямой поддержки BOM (Bill of Materials), т.е. нет четкого способа определить, когда оба репозитория синхронизированы. (Думаю, это то, для чего предназначен git-submodule или repo ).

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

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

Распределенное, одно хранилище

Ресурсы и код находятся в одном репозитории, но в двух разных каталогах.

Преимущества

  • Управление версиями кода и ресурсов взаимосвязано, поэтому спецификация является практичной. Отслеживание с возвратом возможно без особых проблем.

Недостатки

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

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

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

Активы вне репозитория (или вместо этого активы в CMS)

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

Преимущества

  • Не приводит к раздуванию репозитория кода (полезно, например, для git, поскольку он часто проверяет файлы)
  • Обеспечивает гибкую обработку ресурсов, таких как развертывание ресурсов на серверах, предназначенных только для ресурсов
  • Если на CMS с API, ресурсы должны быть относительно простыми для обработки в коде

Недостатки

  • Нет поддержки BOM
  • Нет простой расширенной поддержки обратного отслеживания версий, Если по какой-то причине вы не можете этого сделать, попробуйте поместить одно предложение uses в часть реализации в одном модуле, а другое оставьте в части интерфейса.

3
ответ дан 30 November 2019 в 15:28
поделиться

Не похоже, что TChessBoard.FBoard должен быть массивом TChessPiece, он также может быть из TObject и быть понижен в ChessPiece.pas.

0
ответ дан 30 November 2019 в 15:28
поделиться

Другой подход:

Сделайте свою доску из tBaseChessPiece. Это абстрактно, но содержит определения, на которые вам нужно сослаться.

Внутренняя работа находится в tChessPiece, который происходит от tBaseChessPiece.

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

0
ответ дан 30 November 2019 в 15:28
поделиться

С помощью Delphi Prism вы можете распределить свои пространства имен по отдельным файлам, чтобы вы могли решить эту проблему простым способом.

Модули работают следующим образом. просто фундаментально нарушены их текущей реализацией Delphi. Просто посмотрите, как db.pas нужно было иметь TField, TDataset, TParam и т. Д. В одном чудовищном файле .pas, потому что их интерфейсы ссылаются друг на друга.

В любом случае, вы всегда можете переместить код в отдельный файл и включить его, например, с помощью {$ include ChessBoard_impl.inc} . Таким образом, вы можете разделить материал по файлам и получить отдельные версии через свой vcs. Однако редактировать файлы таким способом немного неудобно.

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

1
ответ дан 30 November 2019 в 15:28
поделиться

Одним из решений может быть введение третьего модуля, который содержит объявления интерфейсов (IBoard и IPiece).

Тогда разделы интерфейса двух модулей с объявлениями классов могут ссылаться на другой класс по его интерфейсу:

TChessBoard = class(TInterfacedObject, IBoard)
private
  FBoard : array [1..8, 1..8] of IPiece;
...
end;

и

TChessPiece = class abstract(TInterfacedObject, IPiece)
public
   procedure GetMoveTargets (BoardPos: TPoint; const Board: IBoard; 
     MoveTargetList: TList <TPoint>);
...
end;

(модификатор const в GetMoveTargets позволяет избежать ненужного подсчета ссылок)

16
ответ дан 30 November 2019 в 15:28
поделиться

Модули Delphi не "принципиально сломаны". А TChessPiece не требует ссылки на игру или доску для определения допустимых целей для перемещения из данной текущей позиции. Ограничения доски (8 рангов и файлов) являются константами предметной области, а не свойствами данного экземпляра доски.

Таким образом, требуется TChessGame , которая инкапсулирует знания, объединяющие понимание доски, фигур и - что особенно важно - правила, но доска и фигуры не нуждаются в знании друг друга ИЛИ игры.

Может показаться заманчивым поместить правила, относящиеся к разным фигурам в классе, для самого типа фигуры, но это это ошибка, imho, поскольку многие правила основаны на взаимодействии с другими фигурами, а в некоторых случаях и с конкретными типами фигур. Такое поведение «большой картины» требует определенной степени недальновидности (читайте: обзор) общего состояния игры, которое не подходит для определенного класса фигур.

например, TChessPawn может определить, что допустимая цель хода - на один или два квадрата вперед или на одно квадратное поле по диагонали вперед, если любой из этих диагональных квадратов занят. Однако, если движение пешки подвергает короля ситуации ПРОВЕРКИ, то пешка вообще не может быть перемещена.

Я бы подошел к этому, просто позволив классу пешки указывать все ВОЗМОЖНЫЕ цели для хода - на 1 или 2 поля вперед. и оба по диагонали вперед квадраты. Затем TChessGame определяет, какой из них является действительным, исходя из занятости этих перемещаемых целей и состояния игры. 2 клетки вперед возможны только в том случае, если пешка находится на своем домашнем ранге, поля вперед заняты БЛОКИРОВАТЬ ход = недействительная цель, незанятые диагональные клетки УПРАВЛЯЮТ ходом, и если какой-либо другой допустимый ход раскрывает короля, то этот ход также недействителен.

Опять же, может возникнуть соблазн поместить общеприменимые правила в базовый класс TChessPiece (например, раскрывает ли данный ход король?), но применение этого правила требует осведомленности об общем состоянии игры, т. е. о размещении других фигур, так что оно более точно относится как обобщенное поведение класса TChessGame , imho

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

24
ответ дан 30 November 2019 в 15:28
поделиться

как насчет этого подхода:

блок шахматной доски:

TBaseChessPiece = class 

public

   procedure GetMoveTargets (BoardPos : TPoint; Board : TChessBoard; MoveTargetList : TList <TPoint>); virtual; abstract;

...

TChessBoard = class
private
  FBoard : array [1..8, 1..8] of TChessPiece;

  procedure InitializePiecesWithDesiredClass;
...

блок фигур:

TYourPiece = class TBaseChessPiece

public 

   procedure GetMoveTargets (BoardPos : TPoint; Board : TChessBoard; MoveTargetList : TList <TPoint>);override;

...

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

0
ответ дан 30 November 2019 в 15:28
поделиться
Другие вопросы по тегам:

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