![]() |
16 апреля 2009, Ник | ||
| Здравствуйте. | ||
| Пусть существуют два класса: Producer и Consumer (поставщик и потребитель). И тот, и другой имеют метод use() (использовать), причем, согласно предметной области, поставщик может использовать только потребителя, а потребитель --- только поставщика. Тело метода use() совершенно одинаково для Producer и Consumer, и методы различаются только типом входных данных ( Consumer *const и Producer *const соответственно). | ||
| Какой из путей наиболее предпочтителен: написать классы по отдельности, дублируя код? (метод 1) или воспользоваться шаблонами (метод 2). (Наследование отметаем, поскольку общего предка у классов Consumer и Producer нет --- ну не связаны они друг с другом никакими родственными отношениями.) | ||
| С уважением, | ||
| Ник. | ||
| P. S. Да, эти классы сильно связаны. Но согласно специфике предметной области, они друг без друга не могут. (Специфика может быть, например, такая: клиент может запросить данные у сервера, но не у клиента. а сервер может запросить данные у одного из своих клиентов, но не у другого сервера.) | ||
| P. P. S. Не судите строго, я только-только осваиваю С++. | ||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | #include <iostream> /////////////////////////////////////////////////////////////////////// // METHOD 1 /////////////////////////////////////////////////////////////////////// class Producer; class Consumer { private: bool wasUsed; public: Consumer(); void use( Producer *const producer ); }; class Producer { private: bool wasUsed; public: Producer(); void use( Consumer *const consumer ); }; Consumer::Consumer(): wasUsed( false ) { } void Consumer::use( Producer *const producer ) { if ( wasUsed ) { return; } wasUsed = true; std::cout << "use" << std::endl; producer->use( this ); } Producer::Producer(): wasUsed( false ) { } void Producer::use( Consumer *const consumer ) { if ( wasUsed ) { return; } wasUsed = true; std::cout << "use" << std::endl; consumer->use( this ); } /////////////////////////////////////////////////////////////////////// // METHOD 2 /////////////////////////////////////////////////////////////////////// template < class U > class User { private: bool wasUsed; public: User(): wasUsed( false ) { } template < class U > void use( U *const user ) { if ( wasUsed ) { return; } wasUsed = true; std::cout << "use" << std::endl; user->use( this ); } }; class NewProducer; class NewConsumer: public User< NewProducer > { }; class NewProducer: public User< NewConsumer > { }; int main() { Producer *producer = new Producer(); Consumer *consumer = new Consumer(); // Displays two messages "use": one from producer, one from consumer. producer->use( consumer ); // Displays nothing, because everything has been already used consumer->use( producer ); // Displays nothing, because everything has been already used producer->use( consumer ); delete consumer; delete producer; std::cout << std::endl; NewProducer *newProducer = new NewProducer(); NewConsumer *newConsumer = new NewConsumer(); // Displays two messages "use": one from producer, one from consumer. newProducer->use( newConsumer ); // Displays nothing, because everything has been already used newConsumer->use( newProducer ); // Displays nothing, because everything has been already used newProducer->use( newConsumer ); delete newConsumer; delete newProducer; char c; std::cin >> c; } |
Шаблонный параметр мембер-функции нельзя называть так же, как и шаблонный параметр класса. Но это так, мелочи. Понимаете, Ник, обсуждать что-то на подобных рафинированных примерах — дело неблагодарное. Наиболее подходящий способ будет всегда зависеть от конкретной ситуации в реальной жизни. Сейчас можно наговорить много всяких умных мыслей, однако, когда дело дойдет до реализации, обязательно всплывет какой-нибудь специфичный момент, который сделает невозможным использование, казалось бы, самого правильного подхода. Копипаст кода это, безусловно, плохо. Однако, то, что сегодня является копипастом, завтра может оказаться двумя разными методами. Уверены ли вы в том, что метод действительно общий? Если нет, то никакой это не копипаст. Если же уверены, то конечно же, код нужно зашарить — второй метод вполне себе ничего. Сделайте общий шаблонный класс, как это сделано во втором методе, однако будьте готовы к тому, что со временем методы «захотят» различаться. P.S. Для человека, который «только-только осваивает C++», очень даже ничего. Продолжайте в том же духе. |
|
| Статистика |
|
|