Использование интерфейсов заставляет реализовать интерфейсы возвращаемых типов? - PullRequest
2 голосов
/ 21 октября 2011

При использовании интерфейсов методы класса реализации вынуждены возвращать интерфейсы или есть способ вернуть объекты?

Пример уточнит:

в единице EmployeeIntf:

IEmployee = interface(IInterface)
  function CoWorker: IEmployee; // We dont know anything about TEmployee here
end;

в единице Сотрудник:

uses EmployeeIntf;
...

TEmployee = class(TObject, IEmployee)
public
  function CoWorker: IEmployee; // Returns an error if set to TEmployee
end;

Текущий код останавливается при ошибке компилятора, если метод возвращает TEmployee: E2211 Объявление 'CoWorker' отличается от объявления в интерфейсе IEmployee (с использованием Delphi 2010)

Вынужден ли метод TEmployee.CoWorker возвращать интерфейс или есть способ вернуть TEmployee, если TEmployee является IEmployee?

Если в этом случае разрешены только интерфейсы, каковы причины проектирования ОО для этого?

[Редактировать]

  • Как спрашивают многие участники, мне не нужно рассчитывать на реферирование на TEmployee, и я хотел бы отделить вышеупомянутый вопрос от любого рассмотрения подсчета реф.

  • Предпосылкой для этого вопроса является необходимость использования очень ограниченного набора открытых функций TEmployee во внешнем компоненте (в отдельном пакете). Я не могу просто импортировать модуль «Сотрудник» в пакете из-за слишком большого количества ненужных зависимостей в разделах пользователей, поэтому я ищу слабосвязанное решение.

Спасибо

Ответы [ 5 ]

3 голосов
/ 21 октября 2011

Вы можете порадовать компилятор, введя условие разрешения метода:

type
  TEmployee = class(TInterfacedObject, IEmployee)
    function IEmployee.CoWorker = IEmployeeCoWorker;
  public
    function IEmployeeCoWorker: IEmployee;
    function CoWorker: TEmployee;
  end;

function TEmployee.IEmployeeCoWorker: IEmployee;
begin
  result := CoWorker;
end;

Конечно, это усложнит код, но если это действительно то, что вам нужно ...

3 голосов
/ 21 октября 2011

методы класса реализации вынуждены возвращать интерфейсы?

Нет, но реализации вынуждены совпадать с сигнатурами определений интерфейса.

isесть способ вернуть объекты?

Да, если вы объявите интерфейс соответствующим образом.

type
  IEmployee = interface
    function CoWorker: TEmployee;
  end;
2 голосов
/ 21 октября 2011

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

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

Начиная с Delphi 2010, вы можете использовать оператор as для получения доступа к объекту реализации.

var
  EmpIntf: IEmployee;
  EmpImp: TEmployee;
...
  EmpImp := EmpIntf as TEmployee;

Остерегайтесь того, что вы теперь подрываете управление временем жизни объекта.Если вы обращаетесь к EmpImp после того, как ссылка на интерфейс обнуляется, у вас возникают проблемы.

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

1 голос
/ 21 октября 2011

Если вы определяете интерфейсную функцию, которая возвращает интерфейс, зачем вам возвращать объект в реализации?

Я считаю, что вы только не знаете, как реализовать "функцию CoWorker: IEmployee».Если это проблема, вот простое решение:

TEmployee = class(TInterfacedObject, IEmployee)
public
  function CoWorker: IEmployee;
end;

function TEmployee.CoWorker: IEmployee;
begin
  Result := TEmployee.Create;
end;

Кстати, вы должны получать объекты реализации интерфейса из TInterfacedObject, а не из TObject.

[EDIT]

Что касается вашего пояснения - вы не можете определить небольшой публичный интерфейс для TEmployee и затем извлечь этот класс из обоих интерфейсов?Как это:

type
  IEmployeePublic = ...
  IEmployee = ...

  TEmployee = class(TInterfacedObject, IEmployee, IEmployeePublic)
    function CoWorker: IEmployeePublic;
  end;
1 голос
/ 21 октября 2011

Delphi не поддерживает ковариантные типы возвращаемых данных. Так что это не имеет ничего общего с интерфейсами, а является просто ограничением самого языка.

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

Если вы используете подсчет ссылок на интерфейсы, у вас есть еще больше причин использовать только ссылки на типы интерфейсов, поскольку смешиваниессылки на объекты могут испортить счет ссылок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...