Delphi: Как скрыть методы предков? - PullRequest
0 голосов
/ 20 января 2011

Это вариант моего предыдущего вопроса о том, как скрыть унаследованные конструкторы . Как скрыть унаследованные методы:

Моделирование по тому, как Delphi позволяет создавать COM-объекты:

CoDOMDocument = class
   class function Create: IXMLDOMDocument2;
end;

У меня есть фабрика, которая создает объект, который реализует интерфейс:

CoCondition = class
public
   class function Create: ICondition;
end;

Это отлично работает и отлично. Он работает нормально, хотя в предке есть метод с именем Create. Это работает, потому что у меня нет ключевого слова overload. Как только я добавлю ключевое слово overload: Delphi позволит унаследованному Create методу "просвечивать":

CoCondition = class
public
   class function Create: ICondition; overload;
end;

Так что теперь CoCondition имеет два метода Create:

class function CoCondition.Create: ICondition;
constructor TObject.Create;

И неоднозначно, по какому из них вы хотите позвонить. Решение, очевидно, состоит в том, чтобы просто не иметь ключевого слова overload ( Почему бы вам ничего не перегружать? ). Ну, получается, я утра перегружаю что-то:

CoCondition = class
public
   class function Create: ICondition; overload;
   class function Create(const ConditionType: TConditionType): ICondition; overload;
   class function Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload;
   class function Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload;
end;

Поскольку у меня есть ключевое слово overload, класс имеет пять перегрузок, а не только четыре, которые я хочу:

class function CoCondition.Create: ICondition;
class function CoCondition.Create(const ConditionType: TConditionType): ICondition; overload;
class function CoCondition.Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload;
class function CoCondition.Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload;
constructor TObject.Create;

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

Как скрыть методы предков?


Я также пытался явно объявить метод предка, но иметь его в защищенном состоянии, чтобы никто не мог получить к нему:

CoCondition = class
protected
    constructor Create; overload;
public
    class function Create(): ICondition; overload;
    class function Create(const ConditionType: TConditionType): ICondition; overload;
    class function Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload; //leaf
    class function Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload; //AND/OR/NOT children
end;

Но это не компилируется из-за неоднозначной перегрузки непараметрических Create().


я тоже считал:

CoCondition = class
public
   class function Make(): ICondition; overload;
   class function Make(const ConditionType: TConditionType): ICondition; overload;
   class function Make(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload; //leaf
   class function Make(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload; //AND/OR/NOT children
end;

Но отверг это.


я мог бы просто выставить объект, который реализует объект:

TCondition = class(TInterfacedObject, ICondition)
...
public
  constructor Create; overload;
  constructor Create(const ConditionType: TConditionType); overload;
  constructor Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant); overload; //leaf
  constructor Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList); overload; //AND/OR/NOT children
end;

Но я думал, что все классные дети прячут свои предметы.

Ответы [ 5 ]

6 голосов
/ 20 января 2011

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

Даже если язык поддерживает скрытие, вы всегда можете обойти его.

Если, например,, если вы создаете класс TAnimal со свойством Name, а затем создаете класс TNamelessAnimal, в котором вы хотите скрыть свойство Name.
Теперь вы можете привести экземпляр TNamelessAnimal вссылка TAnimal и доступ к свойству Name.
Это вполне логично, поскольку TNamelessAnimal является TAnimal и, следовательно, имеет свойство Name.

--jeroen

4 голосов
/ 20 января 2011

Скрытие метода не поддерживается в Delphi просто потому, что это не логично. Предположим, предок TAncestor имеет публичный метод AMethod. Теперь объявите TDescendant = class (TAncestor) и переопределите AMethod как защищенный. Теперь пользователь может просто привести свой TDescendant к TAncestor и получить доступ к методу, который должен был быть скрыт. Я не знаю, поддерживает ли какой-либо объектно-ориентированный язык методы сокрытия в предках, но я сомневаюсь, что они есть.

3 голосов
/ 21 января 2011

Мой лучший способ «спрятать» методы-предки - это объявить интерфейс с именами методов, которые важны для вас ... например:

IMyInterface = interface
  procedure One;
  procedure Two;
end;

Затем реализовать эти методы в своем классе,представление вашего класса как реализации IMyInterface, например:

TMyClass = class( TInterfacedObject, IMyInterface )
PUBLIC
  procedure One;
  procedure Two;
end;

В другом месте вашего кода вместо этого передайте экземпляр вашего класса как IMyInterface (не TMyClass).Это аккуратно скрывает ВСЕ внутренности в вашем классе и разбивает ваш код на хорошо разделенные модули.

Вы будете удивлены, как объявление интерфейса может быть «выглядеть» как класс, то есть со свойствами, напримерзаконно и очень полезно:

IMyInterface = interface
  function GetSomething : integer;
  procedure SetSomething( AValue : integer );
  property  Something : integer; read GetSomething write SetSomething;
end;

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

1 голос
/ 21 января 2011

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

Cheers

0 голосов
/ 20 января 2011

Пометьте вашу новую "версию" именованного метода с помощью директивы reintroduce:

CoCondition = class
public
   class function Create: ICondition; reintroduce;
end;

Это позволяет вам "ввести" имя метода с другими параметрами.

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

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

...