TfrmStandart = class(TForm, IShowStandart)
public
procedure SimpleShow; overload; virtual;
end;
В одном из наследников надо метод SimpleShow перенести в секцию protected (это надо сделать чисто из эстетических соображений). При этом компилятор выдаёт предупреждения. Пробывал использовать директивы компеляции
Что-то я не вижу никакой эстетики в сокрытии метода в наследнике.
Это нарушает самый базис понятия наследования и следовательно объектной парадигмы.
Мне кажется Вам нужно пересмотреть иерархию классов.
Вероятно Вы ошиблись в построении некоторой абстракции.
Здравствуйте, Stepochkin, Вы писали:
S>Что-то я не вижу никакой эстетики в сокрытии метода в наследнике. S>Это нарушает самый базис понятия наследования и следовательно объектной парадигмы. S>Мне кажется Вам нужно пересмотреть иерархию классов. S>Вероятно Вы ошиблись в построении некоторой абстракции.
Хотелось бы добавить, что особенно глупо это выглядит в сочетании с интерфейсом.
Даже если бы это было возможно, то в любой момент разработчик может запросить интерфейс и использовать его!
Здравствуйте, Stepochkin, Вы писали:
S>Что-то я не вижу никакой эстетики в сокрытии метода в наследнике. S>Это нарушает самый базис понятия наследования и следовательно объектной парадигмы. S>Мне кажется Вам нужно пересмотреть иерархию классов. S>Вероятно Вы ошиблись в построении некоторой абстракции.
А по поводу иерархии классов — смотри VCL. классический вариант:
TMyCustomClass = class
protected
property prop001...
............
public
end;
TMyClass = class(TMyCustomClass)
public
property prop001;
end;
нужен наследник с protected prop001? наследуйся от ..Custom..
OAB>>нужен наследник с protected prop001? наследуйся от ..Custom..
S>Ну так там наоборот открывается в наследнике. S>А Вы же хотите закрыть!!!
наверное мы друг друга не совсем поняли...
закрыть НЕЛЬЗЯ потому что это принцип ООП.
можно по-другому разработать структуру классов. наиболее наглядный вариант — то который я привел.
т.е. когда TMyClass не делает ничего кроме как расширения видимости, в свою очередь, если это не нужно, наследование идет от TMyCustomClass у которого видимость ниже, а функционал абсолютно тот же.
Здравствуйте, Stepochkin, Вы писали:
S>Что-то я не вижу никакой эстетики в сокрытии метода в наследнике. S>Это нарушает самый базис понятия наследования и следовательно объектной парадигмы. S>Мне кажется Вам нужно пересмотреть иерархию классов. S>Вероятно Вы ошиблись в построении некоторой абстракции.
Такое желание иногда есть. Оно странно с точки зрения объектной парадигмы, но порождено практикой использования чужого кода.
Допустим, я пишу наследника TPanel, делающего бессмысленным свойство, например, Caption. В этом случае у меня есть ровно два выхода: либо я наследуюсь от TCustomPanel (и обрекаю себя на копирование кода — пусть небольшого фрагмента — для каждой очередной версии дельфы, а также на директивы условной компиляции для работы в нескольких версиях), либо я наследуюсь от TPanel.. и хочу скрыть нечто, что в моем наследнике не нужно.
Идеологически, возможно, мне и следует переписать иерархию классов — но сделать это несколько затруднительно Кроме того, без множественного наследования иногда приходится выбирать наименьшее зло.
Практически же в этом нет ничего страшного — это средство на уровне директивы deprecated. Безусловно, можно добраться до этого свойства/метода — хотя бы приведением к базовому типу — но компилятор так или иначе должен предостерегать от этого шага.
S>Такое желание иногда есть. Оно странно с точки зрения объектной парадигмы, но порождено практикой использования чужого кода. S>Допустим, я пишу наследника TPanel, делающего бессмысленным свойство, например, Caption. В этом случае у меня есть ровно два выхода: либо я наследуюсь от TCustomPanel (и обрекаю себя на копирование кода — пусть небольшого фрагмента — для каждой очередной версии дельфы, а также на директивы условной компиляции для работы в нескольких версиях), либо я наследуюсь от TPanel.. и хочу скрыть нечто, что в моем наследнике не нужно.
Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные
Здравствуйте, Dog, Вы писали:
Dog>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные
Выкрутиться-то можно; обычно в таких элементах нет ничего страшного — просто они бессмысленны. Скажем, скорее всего глупо устанавливать свойство Caption, если мой наследник его нигде и никогда не отображает. Это вопрос именно удобства — не путать пользователя, убрать свойство из Object Inspector, метод — из автозаполнения..
Здравствуйте, 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. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные
ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!
вобщем ребяты, ООП надо чувствовать, а не разглагольствовать об "хотелось бы"...
S>>>Такое желание иногда есть. Оно странно с точки зрения объектной парадигмы, но порождено практикой использования чужого кода. OAB>если код кривой, я бы не рискнул от него наследоваться...
тогда уж использовать
OAB>лучше имплементация + абстрактная фабрика, дабы сэкономить на первых порах время, а потом переписать.
ох, не мне вам говорить, что нет ничего более постоянного чем временное решение
S>>>Допустим, я пишу наследника TPanel, делающего бессмысленным свойство, например, Caption. OAB>ну давайте пофилософствуем OAB>в каком плане бессмысленным? пустое? автоматически заполняемое?
Видимо человек не хочет, что бы у его класса были лишние, ничего не делающие методы и при этом сам наследуется от такого класса.
Dog>>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные OAB>ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!
Я и не предлогал их скрывать. Это больше для человека впоследствии использующего этот код. Мол несунь сюда руки + документация конечно.
Хотя имхо страная ситуация и если она часто возникает тут уж явно не до залатывания дыр.
зы. хотелось бы увидеть хоть один реальный пример где это бы понадобилось.
Dog>>Переопределите в наследнике те методы, что вам не нужны, и сделайте их пустыми или поставьте assert. Если же кто то захочет к ним добраться через указатеть на базовый класс, значит не такие уж они и бессмысленные
OAB>ооочень интересно! мне почему-то казалось, что если метод скрыт — должен ругаться компилятор, а не в процессе выполнения у клиента вдруг программа начинала себя как-то не так вести или вываливалась в дамп!
Кто должен ругаться это ещё вопрос
По этому поводу хочется вспомнить ныне модную парадигму "Test Driven Development".
Не обязательно компилятор. Пусть тесты ругаются.
А вот если методом запрещено пользоваться а Вы им ненароком попользовались и программа не ругнулась, то вот это намного хуже так как фиг её знает что она в этом неопределённом состоянии ещё выкинет и ищи потом ошибку. А бизнес тем временем страдает.
Так что подход с заглушкой сообщающей об ошибке мне кажется вполне приемлимым. И не обязательно вываливаться в дамп. Можно и другие системы логирования придумать
Здравствуйте, 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!
еще и представьте, что это плагин с открытым интерфейсом!
Здравствуйте, 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>еще и представьте, что это плагин с открытым интерфейсом!
Никто ж и не спорит что лучше быть здоровым и богатым чем бедным и больным
то бишь понятно что проектировать нужно правильно
но жизнь такова что иногда приходится на время жертвовать принципами чтобы не страдал бизнес
особенно в условиях использования чужих компонент