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

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

Моделирование аналогично тому, как 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;

Но это не компилируется из-за неоднозначной перегрузки unparametered 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;

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


person Ian Boyd    schedule 20.01.2011    source источник
comment
Что ж, вам просто не следует использовать Create, потому что он используется для конструкторов, а это не конструктор.   -  person David Heffernan    schedule 20.01.2011
comment
›› Но я думал, что все классные дети прячут свои предметы. ‹< Нет, по крайней мере, не в этом примере. Все дети, которые верят, что это заставит их здорово попробовать, но не могут. Как только они это обнаруживают, они ШУТ! стать крутыми детьми.   -  person TheBlastOne    schedule 20.01.2011
comment
@ Дэвид Хеффернан Но Borland сделал это :(   -  person Ian Boyd    schedule 20.01.2011
comment
@Ian Конечно, код, который вы цитируете из Embarcadero, вероятно, был создан импортером typelib. В любом случае они не пытаются перегружать. В любом случае, я считаю, что Create должно быть зарезервировано для конструкторов.   -  person David Heffernan    schedule 20.01.2011
comment
Я бы назвал эти методы CreateInstance и покончил с этим.   -  person The_Fox    schedule 21.01.2011
comment
Почему бы вам ДЕЙСТВИТЕЛЬНО не скрывать вещи и не использовать стиль HAS A FOO вместо IS A FOO? Почему вам действительно нужно использовать наследование здесь, вместо того, чтобы BAR наследовал от FOO, поместите экземпляр FOO внутри BAR и сделайте его закрытым.   -  person Warren P    schedule 21.01.2011
comment
Потому что foo - это Create, чего я не могу скрыть.   -  person Ian Boyd    schedule 24.01.2011


Ответы (5)


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

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

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

- Джерун

person Jeroen Wiert Pluimers    schedule 20.01.2011
comment
Что ж, вы можете скрыть методы-предки; только не когда вы используете overload. Но ответ невозможно сделать, вероятно, настолько верен, насколько и будет. - person Ian Boyd; 20.01.2011
comment
Поскольку это методы класса, этот аргумент не применяется. Нет экземпляров до тех пор, пока функция класса не будет запущена. - person David Heffernan; 20.01.2011
comment
Оно делает; просто приведите ссылку на класс в ссылку на предка, и все готово. Например, когда Name является свойством класса, тогда TAnimalClass = class of TAnimal; AnimalClass: TAnimalClass; AnimalClass := TNamelessAnimal; Writeln(AnimalClass.Name); будет обращаться к свойству класса. То же самое для методов класса. - person Jeroen Wiert Pluimers; 20.01.2011
comment
@Jeroen Ты бы никогда не написал такой код. Вы чаще всего используете class of, когда используете виртуальные конструкторы. - person David Heffernan; 20.01.2011
comment
@ Дэвид: Я знаю, но это уловка, позволяющая обойти методы «сокрытия», если язык допускает такое «сокрытие». - person Jeroen Wiert Pluimers; 20.01.2011
comment
@David et Jeroen: любой код, использующий преимущества метаклассов, полиморфных конструкторов и методов виртуальных классов, может в конечном итоге выполнить такие вещи, как ваш трюк, как само собой разумеющееся. - person Eric Grange; 21.01.2011

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

person Eugene Mayevski 'Callback    schedule 20.01.2011
comment
может просто случай должен быть можно просто cast, я думаю? - person Larry Lustig; 20.01.2011
comment
Поскольку это методы класса, этот аргумент не применяется. Нет экземпляров до тех пор, пока функция класса не будет запущена. - person David Heffernan; 20.01.2011
comment
@ Дэвид и что? Есть сам класс, на который можно ссылаться напрямую. - person Eugene Mayevski 'Callback; 20.01.2011
comment
Я не знаю, поддерживает ли какой-либо объектно-ориентированный язык методы сокрытия в предках, но я сомневаюсь, что они есть. Delphi поддерживает скрытие методов в предках. Вы просто объявляете метод с тем же именем, и, привет! Вы скрыли метод. - person David Heffernan; 20.01.2011
comment
@ Дэвид, нет, ты ошибаешься. Только что протестировано в Delphi 5 - приведение к предку успешно преодолевает любые уловки с методами с тем же именем в потомке. - person Eugene Mayevski 'Callback; 20.01.2011
comment
@Eugene docwiki.embarcadero.com/RADStudio/en/ - person David Heffernan; 20.01.2011
comment
@David У меня нет времени угадывать, что ты имел в виду, но повторяю - возьми компилятор и проверь себя. Я тестировал разные варианты. - person Eugene Mayevski 'Callback; 20.01.2011
comment
@Eugene Я понимаю, что скрытые методы можно найти. Ссылка ведет на документацию Delphi, в которой подробно обсуждается тема скрытых методов. Я действительно согласен с вами и Джеруном, хотя, что прятаться - это вообще плохо, и на самом деле я уже проголосовал за вас обоих ранее сегодня, так что я не совсем согласен с основной идеей любого из ваших ответов! - person David Heffernan; 20.01.2011
comment
@David - В примере кода, который вы связали, вызывается метод с тем же именем предка, IOW - скрытый. Думаю, не совсем то, что вы имеете в виду ... - person Sertac Akyuz; 20.01.2011
comment
@Sertac Это иллюстрирует сокрытие и в точности обсуждаемые здесь проблемы. Да, вы можете скрыть методы, но их все равно можно будет найти, если вы будете искать их. - person David Heffernan; 21.01.2011
comment
@David - пример иллюстрирует сокрытие, а не охоту. И все же в примере метод-предок вызывается как следствие сокрытия. Фактически, скрытие - это вовсе не блокировка доступа к методам предка. - person Sertac Akyuz; 21.01.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;

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

person Brian Frost    schedule 20.01.2011

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

Ваше здоровье

person APZ28    schedule 20.01.2011

Отметьте вашу новую «версию» названного метода директивой «reintroduce»:

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

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

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

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

person Deltics    schedule 20.01.2011