Wzorce: NVI / metoda szablonowa

Czytając mądrą książeczką o której pisałem tutaj, przeczytałem fragment o wzorcu NVI – Non Virtual Interface (nazywanym także metodą szablonową – polskie wiki[słaby art], wersja ang.).
Zamierzam się trzymać tej pierwszej nazwy, ponieważ pod taką nazwą ja go poznałem.
Cała idea polega na tym, że udostępnia się publiczną nie wirtualną metodę, z której może korzystać klient naszej (i potomnych) klasy.
Implementacja tej metody polega na wywołaniu kolejnej metody, która wykonuje właściwe zadanie. Metoda wykonująca właściwe zadanie oznaczona jest jako niepubliczna i wirtualna.
Klasy pochodne mogą i w zasadzie powinny ją przeciążać na własny użytek. Przykładowy kod można zmodyfikować tak, aby metoda była czysto wirtualna, co automatycznie wymusi jej implementacje w klasach potomnych. Ja pozostanę przy przykładzie z książki.

Jaki jest z tego pożytek?
Udostępniając metodę publiczną nie wirtualną, definiujemy jedyny dostęp do funkcjonalności na której zależy użytkownikowi, uniemożliwiamy zmianę tego domyślnego zachowania w klasach pochodnych (przecież nie jest wirtualna). I co najważniejsze (IMO) wszelkie zmiany następują w klasie bazowej, wpływając na wszystkie klasy potomne. A więc bugfix, dodatkowe logowanie, try/catch wszystkiego tego dokonujemy tylko w jednym miejscu. Czy to nie śliczne?

Oczywista oczywistość, jeżeli ktoś będzie chciał nadpisać metodę to ją nadpisze. Wzorce nie są idioto odporne.

Przykładowy kod c++

#include  <iostream> 
using  namespace  std;

class  A
{
public :
 void  DoWork()
 {
  //I can add some code here to bug fix something 
  DoCoreWork();
  //also I can add some log/comment here - all changes will affect me and my inheritace 
 }

private :
 virtual  void  DoCoreWork()
 {
  cout<<"Actually doing some work here!n" ;
 }
};

class  B : public  A
{
 virtual  void  DoCoreWork()
 {
  cout<<"Actually I refuse to workn" ;
 }
};

int  _tmain(int  argc, _TCHAR* argv[])
{
 A* a1 = new  A();
 A* a2 = new  B();

 a1->DoWork();
 a2->DoWork();

 return  0;
}

Oraz przykład dla c#

1: using  System;
2: namespace  Blog
3: {
4:     public  class  A 
5:     {
6:         public  void  DoWork()
7:         {
8:             //The same situation as befere. All fixes and updates can be put here 
9:             CoreDoWork();
10:             //Or here it depends on the case. 
11:         }
12:         protected  virtual  void  CoreDoWork()
13:         {
14:             Console .WriteLine("Actually doing some work" );
15:         }
16:     }
17:     public  class  B  : A 
18:     {
19:         protected  override  void  CoreDoWork()
20:         {
21:             Console .WriteLine("Refuse to work at all" );
22:         }
23:     }
24:     public  class  Program 
25:     {
26:         static  void  Main()
27:         {
28:             A  a1 = new  A ();
29:             A  a2 = new  B ();
30:             a1.DoWork();
31:             a2.DoWork();
32:         }
33:     }
34: }
35: 

Na koniec dodam, że wszelkie podobieństwo kodu do tego w książce nie jest przypadkowe, zostało on z niej zaczerpnięty.

Co o tym sądzicie? Wykorzystacie to kiedyś? Uważacie że jest do bani? Gdzieś się pomyliłem? Macie inne zdanie? Jak zawsze można śmiało komentować.

JS

Dodaj komentarz

This site uses Akismet to reduce spam. Learn how your comment data is processed.