шаблон проектирования, чтобы избежать ненужного добавления абстрактных функций для размещения новых функций - PullRequest
2 голосов
/ 28 мая 2020

В приведенном ниже коде у меня есть абстрактный класс TestAlgModule, который я буду показывать пользователям библиотеки, и есть несколько функций, которые они могут использовать, например VOLUME, MIXER и так далее. Однако предположим, что пользователям нужна новая функция, которая добавляется только в MixerManager, тогда мне нужно добавить ее в TestAlgModule абстрактный класс, и теперь внезапно весь производный класс должен добавить это без каких-либо преимуществ.

Как можно ли этого избежать?

 #include <iostream>                                                                                                                                                                                        
 using namespace std;                                                                                                                                                                                       

 enum {VOLUME, MIXER, UNKNONWN};                                                                                                                                                                            

 class TestAlgModule {                                                                                                                                                                                      
 public:                                                                                                                                                                                                    
     virtual void open(int type) = 0;                                                                                                                                                                       
     virtual void close(int type) = 0;                                                                                                                                                                      
 };                                                                                                                                                                                                         

 class volumeManager : public TestAlgModule                                                                                                                                                                 
 {                                                                                                                                                                                                          
 public:                                                                                                                                                                                                    
     void open(int type) {}                                                                                                                                                                                 
     void close(int type) {}                                                                                                                                                                                
 };                                                                                                                                                                                                         

 class mixerManager : public TestAlgModule                                                                                                                                                                  
 {                                                                                                                                                                                                          
 public:                                                                                                                                                                                                    
     void open(int type) {}                                                                                                                                                                                 
     void close(int type) {}                                                                                                                                                                                
     void differentFunction() {};                                                                                                                                                                           
 };                                                                                                                                                                                                         

 /* users calls this to get algModule and then call functions to get the job done */                                                                                                                                                                                         
 TestAlgModule *getTestAlgModule(int type) {                                                                                                                                                                
     switch(type) {                                                                                                                                                                                         
         case VOLUME:                                                                                                                                                                                       
             return new volumeManager();                                                                                                                                                                    
         case MIXER:                                                                                                                                                                                        
             return new mixerManager();                                                                                                                                                                     
         default:                                                                                                                                                                                           
             break;                                                                                                                                                                                         
     }                                                                                                                                                                                                      
     return nullptr;                                                                                                                                                                                        
 }                                                                                                                                                                                                          

 int main() {                                                                                                                                                                                               
     TestAlgModule * test = getTestAlgModule(MIXER);                                                                                                                                         
     test->open();     
     //test->differentFunction();          this can't be called as it is not part of abstract class and users are exposed only abstract class                                                                                                                                                              
     return 0;                                                                                                                                                                                              
 }                     

Если что-то непонятно, дайте мне знать, и я постараюсь ответить на него. Я ищу лучший способ сделать это, т.е. изменение VolumeManager не должно зависеть от MixerManager.

1 Ответ

1 голос
/ 28 мая 2020

Если вы хотите использовать абстрактную фабрику, как в приведенном выше коде, вам необходимо вернуть указатель на базовый класс. Это верно. И тогда вам нужно вызвать все функции через базовый указатель.

Кстати, пожалуйста, не используйте необработанные указатели. Вместо этого используйте указатели std::unique.

Есть 2 возможных решения.

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

virtual void differentFunction() {}

Из-за других чистых функций базовый класс по-прежнему является абстрактным. Это может привести к жирному интерфейсу. Но во многих случаях это приемлемое решение.

Вторая возможность - снизить указатель базового класса до необходимого вам указателя, используя dynamic_cast и проверяя возвращаемое значение динамического c приведения.

if(mixerManager* mm = dynamic_cast<mixerManager*>(test)) {
    mm->differentFunction();
}

Все это зависит, конечно, от общего дизайна и того, чего вы хотите достичь. Но приведенные выше 2 являются стандартными шаблонами.

Существуют также другие шаблоны проектирования, которые могут соответствовать вашим потребностям, например конструктор или прототип. Пожалуйста, проверьте.

...