Как правильно скрыть public метод
От: DimitrySTD Украина  
Дата: 02.06.04 08:19
Оценка:
Покажу ситуацию на кратком примере. Есть интерфейс
  IShowStandart = interface
    ['{BB16C2C1-3368-4865-B0DC-FE4126E2F4E0}']
    procedure SimpleShow;
  end;


Есть базовая форма его реализующая
  TfrmStandart = class(TForm, IShowStandart)
  public
    procedure SimpleShow; overload; virtual;
  end;


В одном из наследников надо метод SimpleShow перенести в секцию protected (это надо сделать чисто из эстетических соображений). При этом компилятор выдаёт предупреждения. Пробывал использовать директивы компеляции
  protected
    {$HINTS OFF}
    {$WARNINGS OFF}
    procedure SimpleShow; override;
    {$WARNINGS ON}
    {$HINTS ON}

всё равно не помагает. Как вообще сделать правильно.
-- Всего хорошего. Дмитрий Студинский --
ICQ: 175465366
Skype: DimitrySTD
Re: Как правильно скрыть public метод
От: Stepochkin  
Дата: 02.06.04 09:03
Оценка: 2 (1)
Что-то я не вижу никакой эстетики в сокрытии метода в наследнике.
Это нарушает самый базис понятия наследования и следовательно объектной парадигмы.
Мне кажется Вам нужно пересмотреть иерархию классов.
Вероятно Вы ошиблись в построении некоторой абстракции.
Re[2]: Как правильно скрыть public метод
От: Oleg A. Bachin Украина  
Дата: 02.06.04 11:19
Оценка: 2 (1)
Здравствуйте, Stepochkin, Вы писали:

S>Что-то я не вижу никакой эстетики в сокрытии метода в наследнике.

S>Это нарушает самый базис понятия наследования и следовательно объектной парадигмы.
S>Мне кажется Вам нужно пересмотреть иерархию классов.
S>Вероятно Вы ошиблись в построении некоторой абстракции.

Хотелось бы добавить, что особенно глупо это выглядит в сочетании с интерфейсом.
Даже если бы это было возможно, то в любой момент разработчик может запросить интерфейс и использовать его!
Best regards,
Oleg A. Bachin
Re[2]: Как правильно скрыть public метод
От: Oleg A. Bachin Украина  
Дата: 02.06.04 11:42
Оценка:
Здравствуйте, Stepochkin, Вы писали:

S>Что-то я не вижу никакой эстетики в сокрытии метода в наследнике.

S>Это нарушает самый базис понятия наследования и следовательно объектной парадигмы.
S>Мне кажется Вам нужно пересмотреть иерархию классов.
S>Вероятно Вы ошиблись в построении некоторой абстракции.

А по поводу иерархии классов — смотри VCL. классический вариант:

TMyCustomClass = class
protected
  property prop001...
 ............
public
end;

TMyClass = class(TMyCustomClass)
public
  property prop001;
end;


нужен наследник с protected prop001? наследуйся от ..Custom..
Best regards,
Oleg A. Bachin
Re[3]: Как правильно скрыть public метод
От: Stepochkin  
Дата: 02.06.04 11:49
Оценка:
OAB>А по поводу иерархии классов — смотри VCL. классический вариант:

OAB>
OAB>TMyCustomClass = class
OAB>protected
OAB>  property prop001...
OAB> ............
OAB>public
OAB>end;

OAB>TMyClass = class(TMyCustomClass)
OAB>public
OAB>  property prop001;
OAB>end;

OAB>


OAB>нужен наследник с protected prop001? наследуйся от ..Custom..


Ну так там наоборот открывается в наследнике.
А Вы же хотите закрыть!!!
Re[4]: Как правильно скрыть public метод
От: Oleg A. Bachin Украина  
Дата: 02.06.04 11:59
Оценка:
Здравствуйте, Stepochkin, Вы писали:

OAB>>А по поводу иерархии классов — смотри VCL. классический вариант:


OAB>>
OAB>>TMyCustomClass = class
OAB>>protected
OAB>>  property prop001...
OAB>> ............
OAB>>public
OAB>>end;

OAB>>TMyClass = class(TMyCustomClass)
OAB>>public
OAB>>  property prop001;
OAB>>end;

OAB>>


OAB>>нужен наследник с protected prop001? наследуйся от ..Custom..


S>Ну так там наоборот открывается в наследнике.

S>А Вы же хотите закрыть!!!

наверное мы друг друга не совсем поняли...
закрыть НЕЛЬЗЯ потому что это принцип ООП.
можно по-другому разработать структуру классов. наиболее наглядный вариант — то который я привел.
т.е. когда TMyClass не делает ничего кроме как расширения видимости, в свою очередь, если это не нужно, наследование идет от TMyCustomClass у которого видимость ниже, а функционал абсолютно тот же.
Best regards,
Oleg A. Bachin
Re[2]: Как правильно скрыть public метод
От: Softwarer http://softwarer.ru
Дата: 02.06.04 12:24
Оценка:
Здравствуйте, Stepochkin, Вы писали:

S>Что-то я не вижу никакой эстетики в сокрытии метода в наследнике.

S>Это нарушает самый базис понятия наследования и следовательно объектной парадигмы.
S>Мне кажется Вам нужно пересмотреть иерархию классов.
S>Вероятно Вы ошиблись в построении некоторой абстракции.

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

Допустим, я пишу наследника TPanel, делающего бессмысленным свойство, например, Caption. В этом случае у меня есть ровно два выхода: либо я наследуюсь от TCustomPanel (и обрекаю себя на копирование кода — пусть небольшого фрагмента — для каждой очередной версии дельфы, а также на директивы условной компиляции для работы в нескольких версиях), либо я наследуюсь от TPanel.. и хочу скрыть нечто, что в моем наследнике не нужно.

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

Практически же в этом нет ничего страшного — это средство на уровне директивы deprecated. Безусловно, можно добраться до этого свойства/метода — хотя бы приведением к базовому типу — но компилятор так или иначе должен предостерегать от этого шага.
Re[3]: Как правильно скрыть public метод
От: Dog  
Дата: 02.06.04 12:55
Оценка:
S>Такое желание иногда есть. Оно странно с точки зрения объектной парадигмы, но порождено практикой использования чужого кода.
S>Допустим, я пишу наследника TPanel, делающего бессмысленным свойство, например, Caption. В этом случае у меня есть ровно два выхода: либо я наследуюсь от TCustomPanel (и обрекаю себя на копирование кода — пусть небольшого фрагмента — для каждой очередной версии дельфы, а также на директивы условной компиляции для работы в нескольких версиях), либо я наследуюсь от TPanel.. и хочу скрыть нечто, что в моем наследнике не нужно.
Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные
Re[4]: Как правильно скрыть public метод
От: Softwarer http://softwarer.ru
Дата: 02.06.04 13:14
Оценка:
Здравствуйте, Dog, Вы писали:

Dog>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные


Выкрутиться-то можно; обычно в таких элементах нет ничего страшного — просто они бессмысленны. Скажем, скорее всего глупо устанавливать свойство Caption, если мой наследник его нигде и никогда не отображает. Это вопрос именно удобства — не путать пользователя, убрать свойство из Object Inspector, метод — из автозаполнения..
Re[4]: Как правильно скрыть public метод
От: Oleg A. Bachin Украина  
Дата: 02.06.04 15:13
Оценка:
Здравствуйте, Dog, Вы писали:

S>>Такое желание иногда есть. Оно странно с точки зрения объектной парадигмы, но порождено практикой использования чужого кода.

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

S>>Допустим, я пишу наследника TPanel, делающего бессмысленным свойство, например, Caption.

ну давайте пофилософствуем
в каком плане бессмысленным? пустое? автоматически заполняемое?

S>>В этом случае у меня есть ровно два выхода: либо я наследуюсь от TCustomPanel

S>>(и обрекаю себя на копирование кода — пусть небольшого фрагмента — для каждой очередной версии дельфы, а также на директивы условной компиляции для работы в нескольких версиях),

ага! опять вернемся к предыдущему моему постингу ...
если что-либо переписывать — значит базовый класс TCustomPanel не имеет полный функционал, а значит в этом случае в проектировании поленились борланды...

S>>либо я наследуюсь от TPanel.. и хочу скрыть нечто, что в моем наследнике не нужно.

нет. не понимаю... давайте вместе попробуем...

procedure MyProc(p: TPanel);
begin
end;

type
  TYourPanel = class(TPanel)
  // here hide some props, func, proc etc... 
  end;

var
  p1: TYourPanel;
  p2: TPanel;
begin
  p1 := TYourPanel.Create;
  MyProc(p1); // что должен сказать компилятор

  p2 := TYourPanel.Create;
  MyProc(p2); // а здесь !?!?!?!?!


Dog>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные


ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!


вобщем ребяты, ООП надо чувствовать, а не разглагольствовать об "хотелось бы"...
Best regards,
Oleg A. Bachin
Re[5]: Как правильно скрыть public метод
От: Dog  
Дата: 02.06.04 16:52
Оценка:
S>>>Такое желание иногда есть. Оно странно с точки зрения объектной парадигмы, но порождено практикой использования чужого кода.
OAB>если код кривой, я бы не рискнул от него наследоваться...
тогда уж использовать

OAB>лучше имплементация + абстрактная фабрика, дабы сэкономить на первых порах время, а потом переписать.

ох, не мне вам говорить, что нет ничего более постоянного чем временное решение

S>>>Допустим, я пишу наследника TPanel, делающего бессмысленным свойство, например, Caption.

OAB>ну давайте пофилософствуем
OAB>в каком плане бессмысленным? пустое? автоматически заполняемое?
Видимо человек не хочет, что бы у его класса были лишние, ничего не делающие методы и при этом сам наследуется от такого класса.

Dog>>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные

OAB>ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!
Я и не предлогал их скрывать. Это больше для человека впоследствии использующего этот код. Мол несунь сюда руки + документация конечно.
Хотя имхо страная ситуация и если она часто возникает тут уж явно не до залатывания дыр.

зы. хотелось бы увидеть хоть один реальный пример где это бы понадобилось.
Re[5]: Как правильно скрыть public метод
От: Stepochkin  
Дата: 03.06.04 05:08
Оценка:
Dog>>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные

OAB>ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!


Кто должен ругаться это ещё вопрос
По этому поводу хочется вспомнить ныне модную парадигму "Test Driven Development".
Не обязательно компилятор. Пусть тесты ругаются.
А вот если методом запрещено пользоваться а Вы им ненароком попользовались и программа не ругнулась, то вот это намного хуже так как фиг её знает что она в этом неопределённом состоянии ещё выкинет и ищи потом ошибку. А бизнес тем временем страдает.
Так что подход с заглушкой сообщающей об ошибке мне кажется вполне приемлимым. И не обязательно вываливаться в дамп. Можно и другие системы логирования придумать
Re[6]: Как правильно скрыть public метод
От: Oleg A. Bachin Украина  
Дата: 03.06.04 06:59
Оценка:
Здравствуйте, Stepochkin, Вы писали:

Dog>>>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные


OAB>>ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!


S>Кто должен ругаться это ещё вопрос

S>По этому поводу хочется вспомнить ныне модную парадигму "Test Driven Development".
S>Не обязательно компилятор. Пусть тесты ругаются.

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

procedure MyProc(p: TPanel);
begin
end;

type
  TYourPanel = class(TPanel)
  // here hide some props, func, proc etc... 
  end;

var
  p1: TYourPanel;
  p2: TPanel;
begin
  p1 := TYourPanel.Create;
  MyProc(p1); // что должен сказать компилятор

  p2 := TYourPanel.Create;
  MyProc(p2); // а здесь !?!?!?!?!


допустим вы пишете тест для MyProc...
с вашей точки зрения, при создании КАЖДОГО наследника базового класса, надо переписывать этот тест?
тогда что это? тестирование ф-ции или тестирование класса? я лично писал ф-цию, и хочу быть уверенным, что она работает ВСЕГДА. и тестировать я буду только ее! а кто пишет класс — это его проблема! (мы сейчас не говорим от абстрактных классах).

S>А вот если методом запрещено пользоваться а Вы им ненароком попользовались и программа не ругнулась, то вот это намного хуже так как фиг её знает что она в этом неопределённом состоянии ещё выкинет и ищи потом ошибку. А бизнес тем временем страдает.


можно пояснить эту связку "запрещено пользоваться" + "ненароком попользовались" на предыдущем примере?

S>Так что подход с заглушкой сообщающей об ошибке мне кажется вполне приемлимым. И не обязательно вываливаться в дамп. Можно и другие системы логирования придумать


опять же, на предыдущем примере...

прикидываю такую ситуацию:

TDolphin = class(TObject) // не будем расписывать...
...
  procedure swim();
...
end;

TGreyDolphin = class(TDolphin)
  procedure swim(); 
    begin
      assert(...);
    end;
end;

procedure SwimAll(ad: array [...] of TDolphin);
begin
  for each ad.swim;
end;

begin
  SwimmAll(...)
  AV: "в стае гибрид! он не плавает, потому что серый!"
end.


да поймите же Вы, что если есть теоретически такая возможность, что дельфин не сможет плыть, то это должно быть продумано в базовом классе, либо в базовом классе должна быть заглушка, либо это AV!

еще и представьте, что это плагин с открытым интерфейсом!
Best regards,
Oleg A. Bachin
Re[7]: Как правильно скрыть public метод
От: Stepochkin  
Дата: 03.06.04 08:28
Оценка:
Здравствуйте, Oleg A. Bachin, Вы писали:

OAB>Здравствуйте, Stepochkin, Вы писали:


Dog>>>>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные


OAB>>>ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!


S>>Кто должен ругаться это ещё вопрос

S>>По этому поводу хочется вспомнить ныне модную парадигму "Test Driven Development".
S>>Не обязательно компилятор. Пусть тесты ругаются.

OAB>хм... вы нарочно вырезали мой пример или как?

OAB>вот с таким подходом тесты превращаются из полезного инструмента в модную парадигму.
OAB>повторюсь еще раз:

OAB>
OAB>procedure MyProc(p: TPanel);
OAB>begin
OAB>end;

OAB>type
OAB>  TYourPanel = class(TPanel)
OAB>  // here hide some props, func, proc etc... 
OAB>  end;

OAB>var
OAB>  p1: TYourPanel;
OAB>  p2: TPanel;
OAB>begin
OAB>  p1 := TYourPanel.Create;
OAB>  MyProc(p1); // что должен сказать компилятор

OAB>  p2 := TYourPanel.Create;
OAB>  MyProc(p2); // а здесь !?!?!?!?!
OAB>


OAB>допустим вы пишете тест для MyProc...

OAB>с вашей точки зрения, при создании КАЖДОГО наследника базового класса, надо переписывать этот тест?
OAB>тогда что это? тестирование ф-ции или тестирование класса? я лично писал ф-цию, и хочу быть уверенным, что она работает ВСЕГДА. и тестировать я буду только ее! а кто пишет класс — это его проблема! (мы сейчас не говорим от абстрактных классах).

Пишите тесты для данного приложения и убеждаетесь что Вы не вызвали запрещенный метод.
Какие проблемы
А по поводу "ВСЕГДА" — это Вы батенька большой оптимист
Я лишь сказал что ругаться должен не обязательно компилятор.
Многие проверки можно перекладывать на тесты.
В любом случае Вы же пишите их для каждого приложения — я надеюсь

Например программы на Smalltalk или Python — языках без строгой типизации — писать намного быстрее чем на С++ или Java. Менее объектно-ориентированными они от этого не становятся. И при правильном применении Test-Driven подхода надёжность также не страдает.

S>>А вот если методом запрещено пользоваться а Вы им ненароком попользовались и программа не ругнулась, то вот это намного хуже так как фиг её знает что она в этом неопределённом состоянии ещё выкинет и ищи потом ошибку. А бизнес тем временем страдает.


OAB>можно пояснить эту связку "запрещено пользоваться" + "ненароком попользовались" на предыдущем примере?


Например Вы решили не пользоваться каким-то аспектом функционирования интерфейса как и было в случае описанном в изначальном посте.
А уж что значит "ненароком попользовались" не мне Вам объяснять

S>>Так что подход с заглушкой сообщающей об ошибке мне кажется вполне приемлимым. И не обязательно вываливаться в дамп. Можно и другие системы логирования придумать


OAB>опять же, на предыдущем примере...


OAB>прикидываю такую ситуацию:


OAB>
OAB>TDolphin = class(TObject) // не будем расписывать...
OAB>...
OAB>  procedure swim();
OAB>...
OAB>end;

OAB>TGreyDolphin = class(TDolphin)
OAB>  procedure swim(); 
OAB>    begin
OAB>      assert(...);
OAB>    end;
OAB>end;

OAB>procedure SwimAll(ad: array [...] of TDolphin);
OAB>begin
OAB>  for each ad.swim;
OAB>end;

OAB>begin
OAB>  SwimmAll(...)
OAB>  AV: "в стае гибрид! он не плавает, потому что серый!"
OAB>end.

OAB>


OAB>да поймите же Вы, что если есть теоретически такая возможность, что дельфин не сможет плыть, то это должно быть продумано в базовом классе, либо в базовом классе должна быть заглушка, либо это AV!


OAB>еще и представьте, что это плагин с открытым интерфейсом!


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