Здравствуйте, minorlogic, Вы писали:
M>Мне тоже в свое время хотелось узнать об преимуществах NVI , особенно в свете того что некоторые авторы советуют его применять ВСЕГДА когда есть виртуальная функция.
M>К сожалению , внятной аргументации я тогда не получил.
using System;
namespace Lib
{
public class Base
{
public virtual void Hello()
{
Console.WriteLine("Base::Hello()");
}
}
public class Derived : Base
{
public override void Hello()
{
Console.WriteLine("Derived::Hello()");
}
}
}
// Program.cpp : main project file.#include"stdafx.h"using namespace System;
using namespace Lib;
int main(array<System::String ^> ^args)
{
Derived^ derived = gcnew Derived();
derived->Base::Hello();
return 0;
}
Здравствуйте, minorlogic, Вы писали:
M>Я считаю что ИНОГДА NVI может быть полезен , но скорее как шаблонная функция. и уж точно он не полезен ВСЕГДА , в чем сатер пытается безуспешно читателей убедить.
То есть ты считаешь нормальным, что у класса Derived кто-угодно может вызвать вируальный методы из Base, несмотря на то, что он был перекрыт в Derived?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Какие преимущества от NVI шаблона?
От:
Аноним
Дата:
06.04.07 11:58
Оценка:
Вот классическая реализация
public class Base
{
public void DoWork()
{
CoreDoWork();
}
protected virtual void CoreDoWork()
{
Console.WriteLine( "Base.DoWork()" );
}
}
public class Derived : Base
{
protected override void CoreDoWork()
{
Console.WriteLine( "Derived.DoWork()" );
}
}
//Применение шаблона NVIpublic class EntryPoint
{
static void Main()
{
Base b = new Derived();
b.DoWork();
}
}
Чем такая реализация лучше этой?
public class Base
{
public virtual void DoWork()
{
Console.WriteLine( "Base.DoWork()" );
}
}
public class Derived : Base
{
public override void DoWork()
{
Console.WriteLine( "Derived.DoWork()" );
}
}
public class EntryPoint
{
static void Main()
{
Base b = new Derived();
b.DoWork();
}
}
Здравствуйте, Аноним, Вы писали:
bnk>>В вашем случае — ничем. bnk>>А например если вот так, тогда становится понятно:
А>Так это уже тогда Template Method
Тогда извиняюсь... Не очень силен в терминологии...
Я тоже наверное тогда не знаю зачам такое может понадобиться...
Какой смысл делать метод, которрый только и делает что вызывает другой метод?
По-моему это совершенно бессмысленно
Для понимания преимуществ этого паттерна надо перейти на более высокий уровень абстракции. В данном случае мы имеем преимущество сокрытия информации о внутреннем устройстве иерархии Base, Derived.
Я думаю это решение можно применять в областях кода, чреватых частыми изменениями. Для примера, возьмём ситуацию, когда было принято решение отказаться от виртуальности метода DoWork(), или о сворачивании иерархии в один класс. Мне кажется, что первое решение очень сильно облегчит рефакторинг кода.
Мне тоже в свое время хотелось узнать об преимуществах NVI , особенно в свете того что некоторые авторы советуют его применять ВСЕГДА когда есть виртуальная функция.
К сожалению , внятной аргументации я тогда не получил.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, minorlogic, Вы писали:
M>>Наверное я очень туп но я опять не понял , что вы мне пытались продемонстрировать ? Или ошиблись веткой ?
L>Я пытался продемонстрировать, что пудличные виртуальные функции есть зло, т.к. перекрытую функцию можно "обойти".
С подобной агрументацией я вообще могу сказать что программировать плохо , потому что ошибиться можно. А уж как плохо программировать на C++ если там разрешены статический касты произвольных типов!!!
Здравствуйте, minorlogic, Вы писали:
M>Меня опять это не убедило.
M>Это очень хорошо , точ ее можно обойти.
Как правило, человек, перекрывающий какой-либо метод расчитывает на то, что тот, кто использует экземплр его класса работает через перекрытый метод, а не через базовый метод.
M>Это в дизайне языка и идеалогии программирования на С++.
Здравствуйте, minorlogic, Вы писали:
M>С подобной агрументацией я вообще могу сказать что программировать плохо , потому что ошибиться можно. А уж как плохо программировать на C++ если там разрешены статический касты произвольных типов!!!
Если есть способ избежать ошибки, то по-моему глупо им не воспользоваться.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, minorlogic, Вы писали:
M>>Но вы же явно указали что надо вызвать ? M>>Base::Hello();
L>по твоей логике выходит, что запрещать обращение к приватным членам тоже не нужно — ты же сам явно обратился к приватному члену.
C++ запрещает обращаться к приватным членам. Ты пример написла вообща для какого языка ? я так понял для C# ?
Здравствуйте, minorlogic, Вы писали:
M>>>Но вы же явно указали что надо вызвать ? M>>>Base::Hello();
L>>по твоей логике выходит, что запрещать обращение к приватным членам тоже не нужно — ты же сам явно обратился к приватному члену.
M>C++ запрещает обращаться к приватным членам.
Вах, а зачем? Ты же явно указываешь, что надо вызвать
M>Ты пример написла вообща для какого языка ? я так понял для C# ?
Там смесь из C#-а и плюсов. В C# необходимость использования protected virtual методов еще менее очевидна, т.к. сам C# не позволяет вызвать метод базового класса в обход метода наследника. В то же время .Net этого не запрещает, что я и продемонстрировал на примере C++.
public class Base
{
public void Work()
{
DoWork();
}
protected virtual void DoWork()
{
Console.WriteLine( "Base.Work()" );
}
}
public class Derived : Base
{
public void Job()
{
}
protected override void DoWork()
{
Console.WriteLine( "Derived.Work()" );
}
}
Читатель класса Derived понимает, что DoWork() — специализирует Work(), в то время как Job() — расширяет набор операций базового класса. Иными словами DoWork() определяет специфику поведения операции Work() сохраняя инварианты присущие базовому классу, тогда как Job() — операция не присущая базовому классу, эта операция расширяет набор допустимых действий. Сравниваем с
public class Derived : Base
{
public virtual void Job()
{
Console.WriteLine( "Derived.Job()" );
}
}
Читателю класса не понять: Job() — расширяет или специализирует поведение? Т.е. надо посмотреть а что оно там в Base.
А>//Применение шаблона NVI А>public class EntryPoint А>{ А> static void Main() А> { А> Base b = new Derived(); А> b.DoWork(); А> } А>} А>[/c#]
А>Чем такая реализация лучше этой? А>
А>public class Base
А>{
А> public virtual void DoWork()
А> {
А> Console.WriteLine( "Base.DoWork()" );
А> }
А>}
А>public class Derived : Base
А>{
А> public override void DoWork()
А> {
А> Console.WriteLine( "Derived.DoWork()" );
А> }
А>}
А>public class EntryPoint
А>{
А> static void Main()
А> {
А> Base b = new Derived();
А> b.DoWork();
А> }
А>}
А>
Здравствуйте, afurmanov, Вы писали:
A>Читатель класса Derived понимает, что DoWork() — специализирует Work(), в то время как Job() — расширяет набор операций базового класса. Иными словами DoWork() определяет специфику поведения операции Work() сохраняя инварианты присущие базовому классу, тогда как Job() — операция не присущая базовому классу, эта операция расширяет набор допустимых действий. Сравниваем с
A>
A>public class Derived : Base
A>{
A> public virtual void Job()
A> {
A> Console.WriteLine( "Derived.Job()" );
A> }
A>}
A>
A>Читателю класса не понять: Job() — расширяет или специализирует поведение? Т.е. надо посмотреть а что оно там в Base.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, afurmanov, Вы писали:
A>>Читатель класса Derived понимает, что DoWork() — специализирует Work(), в то время как Job() — расширяет набор операций базового класса. Иными словами DoWork() определяет специфику поведения операции Work() сохраняя инварианты присущие базовому классу, тогда как Job() — операция не присущая базовому классу, эта операция расширяет набор допустимых действий. Сравниваем с
A>>
A>>public class Derived : Base
A>>{
A>> public virtual void Job()
A>> {
A>> Console.WriteLine( "Derived.Job()" );
A>> }
A>>}
A>>
A>>Читателю класса не понять: Job() — расширяет или специализирует поведение? Т.е. надо посмотреть а что оно там в Base.
L>Пример некорректен.
Читателю FileLogger очевидно где есть имплементация, а где есть публичный интерфейс. В случае же с
FileLogger2, Write() — это что, имплементация или этот метод расширяет интерфейс ILogger2 ?
Здравствуйте, minorlogic, Вы писали:
M>Мне тоже в свое время хотелось узнать об преимуществах NVI , особенно в свете того что некоторые авторы советуют его применять ВСЕГДА когда есть виртуальная функция. M>К сожалению , внятной аргументации я тогда не получил.
Здравствуйте, <Аноним>, Вы писали:
А>Вот классическая реализация
А>
А>public class Base
А>{
А> public void DoWork()
А> {
А> CoreDoWork();
А> }
А> protected virtual void CoreDoWork()
А> {
А> Console.WriteLine( "Base.DoWork()" );
А> }
А>}
А>public class Derived : Base
А>{
А> protected override void CoreDoWork()
А> {
А> Console.WriteLine( "Derived.DoWork()" );
А> }
А>}
А>//Применение шаблона NVI
А>public class EntryPoint
А>{
А> static void Main()
А> {
А> Base b = new Derived();
А> b.DoWork();
А> }
А>}
А>
А>Чем такая реализация лучше этой? А>
А>public class Base
А>{
А> public virtual void DoWork()
А> {
А> Console.WriteLine( "Base.DoWork()" );
А> }
А>}
А>public class Derived : Base
А>{
А> public override void DoWork()
А> {
А> Console.WriteLine( "Derived.DoWork()" );
А> }
А>}
А>public class EntryPoint
А>{
А> static void Main()
А> {
А> Base b = new Derived();
А> b.DoWork();
А> }
А>}
А>
Несовсем корректный пример. Основная идея в том, что у вас есть некоторая общая последовательность действий, но с разными вариантами реализации. Например так:
Здравствуйте, Rutven, Вы писали:
R>Несовсем корректный пример. Основная идея в том, что у вас есть некоторая общая последовательность действий, но с разными вариантами реализации. Например так:
хъ
Я вот тоже так думал, но автор уже написал, что то такой пример называется уже не NVI, а "шаблонный метод" ("Template method").
Так что не катит... Насколько я понял, NVI — это когда реализация не-виртуальной функция базового класса не содержит ничего кроме вызова соответствующей виртуальной функции...
IMHO, смысл у такой реализации только один —
чтобы была возможность в последующем преобразовать ее в "полноценный" шаблонный метод.
Здравствуйте, bnk, Вы писали:
bnk>Здравствуйте, Rutven, Вы писали:
R>>Несовсем корректный пример. Основная идея в том, что у вас есть некоторая общая последовательность действий, но с разными вариантами реализации. Например так:
bnk>хъ
bnk>Я вот тоже так думал, но автор уже написал, что то такой пример называется уже не NVI, а "шаблонный метод" ("Template method"). bnk>Так что не катит... Насколько я понял, NVI — это когда реализация не-виртуальной функция базового класса не содержит bnk>ничего кроме вызова соответствующей виртуальной функции...
bnk>IMHO, смысл у такой реализации только один — bnk>чтобы была возможность в последующем преобразовать ее в "полноценный" шаблонный метод.
На самом деле, это я лоханулся , мой пример — это как раз Template method, а тот, что привели вы и есть NVI.
The template method is strongly related to the NVI (Non-Virtual Interface) pattern. The NVI pattern recognizes the benefits of a non-abstract method invoking the subordinate abstract methods. This level of indirection allows for pre and post operations relative to the abstract operations both immediately and with future unforseen changes.
, задача 18 — виртуальность). В нём отлично всё разъяснено. M>>Саттер вообще никакой внятной аргументации не приводит , даже без примеров.
_FR>Ты не прав. Начни читать на 119ой странице со слов _FR>
Открытая виртуальная функция вынуждена выполнять две работы…
_FR>Далее следует 120ая и 12ая страницы объяснений. Если ты их за доводы не считаешь, то извини
Я считаю что ИНОГДА NVI может быть полезен , но скорее как шаблонная функция. и уж точно он не полезен ВСЕГДА , в чем сатер пытается безуспешно читателей убедить.
Здравствуйте, minorlogic, Вы писали:
M>Я считаю что ИНОГДА NVI может быть полезен , но скорее как шаблонная функция. и уж точно он не полезен ВСЕГДА , в чем сатер пытается безуспешно читателей убедить.
А аргументировать "Я считаю" чем-либо, кроме как апперкэйсом по силам? Сказать, что, мол "старик ошибается, гонит и ваще он не прав" имеет возможность каждый и цена этому ноль и не интересно.
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, minorlogic, Вы писали:
M>>Я считаю что ИНОГДА NVI может быть полезен , но скорее как шаблонная функция. и уж точно он не полезен ВСЕГДА , в чем сатер пытается безуспешно читателей убедить.
L>То есть ты считаешь нормальным, что у класса Derived кто-угодно может вызвать вируальный методы из Base, несмотря на то, что он был перекрыт в Derived?
Я считаю что это замечательно иметь такую возможность !
Здравствуйте, _FRED_, Вы писали:
_FR>А аргументировать "Я считаю" чем-либо, кроме как апперкэйсом по силам? Сказать, что, мол "старик ошибается, гонит и ваще он не прав" имеет возможность каждый и цена этому ноль и не интересно.
Здравствуйте, minorlogic, Вы писали:
L>>То есть ты считаешь нормальным, что у класса Derived кто-угодно может вызвать вируальный методы из Base, несмотря на то, что он был перекрыт в Derived?
M>Я считаю что это замечательно иметь такую возможность !
Ну приплыли. Дай угадаю твое следующее желание — получить доступ к приватным членам?
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, minorlogic, Вы писали:
L>>>То есть ты считаешь нормальным, что у класса Derived кто-угодно может вызвать вируальный методы из Base, несмотря на то, что он был перекрыт в Derived?
M>>Я считаю что это замечательно иметь такую возможность !
L>Ну приплыли. Дай угадаю твое следующее желание — получить доступ к приватным членам?
Я могу тебя удивить , но и такая есть возможность в C++ . Вообще , я бы советовал не коверкать язык к неприспособленным конструкциям , а просто поменять язык.
Здравствуйте, minorlogic, Вы писали:
M>>>Я считаю что это замечательно иметь такую возможность !
L>>Ну приплыли. Дай угадаю твое следующее желание — получить доступ к приватным членам?
M>Я могу тебя удивить , но и такая есть возможность в C++ .
Фрэнды не считаются. Если бы вызов перекрытых методов был только для фрэндов, необходимости в NVI не возникло бы.
M>Вообще , я бы советовал не коверкать язык к неприспособленным конструкциям , а просто поменять язык.
Я-то уже поменял на C#. Но вот только дух C++ преследует и тут — в .Net-е оставили возможность вызвать перекрытый метод.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, minorlogic, Вы писали:
M>>>>Я считаю что это замечательно иметь такую возможность !
L>>>Ну приплыли. Дай угадаю твое следующее желание — получить доступ к приватным членам?
M>>Я могу тебя удивить , но и такая есть возможность в C++ .
L>Фрэнды не считаются. Если бы вызов перекрытых методов был только для фрэндов, необходимости в NVI не возникло бы.
А нет такой необходимостм....
M>>Вообще , я бы советовал не коверкать язык к неприспособленным конструкциям , а просто поменять язык.
L>Я-то уже поменял на C#. Но вот только дух C++ преследует и тут — в .Net-е оставили возможность вызвать перекрытый метод.
Видимо строители языков заблуждаются , жаль что получилось пролить на них свет познанья ...
Здравствуйте, minorlogic, Вы писали:
L>>Фрэнды не считаются. Если бы вызов перекрытых методов был только для фрэндов, необходимости в NVI не возникло бы.
M>А нет такой необходимостм....
Если бы не было необходимости, никому в голову не пришлось бы изобретать NVI.
M>>>Вообще , я бы советовал не коверкать язык к неприспособленным конструкциям , а просто поменять язык.
L>>Я-то уже поменял на C#. Но вот только дух C++ преследует и тут — в .Net-е оставили возможность вызвать перекрытый метод.
M>Видимо строители языков заблуждаются , жаль что получилось пролить на них свет познанья ...