c++ - Refactor code that violates "Needless Repition" principle -
assume class animal eat, sleep , make noise. assume class mammal : public animal makesbaby assume mammal eat, sleep , make noise inherits animal.
this code extended code presented in this question answered yesterday dan masek.
the problems code are:
- mammal can't inherit animal (compile error)
- mammal cannot eat, sleep or make noise
- code suffers "needless repetition", meeting scorn , derision of uncle bob martin.
i want code excellent possible, stuck.
i think similarities between 2 classes center around typedef defines function pointer member in class. tried templating this, ran numerous compile errors, demonstrating utter failure comprehend how solve problem. hence post.
for saw previous post, have added #ifdef disable printing (this arduino code, std not available), , added asserts wherever could. added mammal class.
// set false suppress serial.print output #define tracing true class animal { public: enum { cmd_eat = 1 , cmd_sleep , cmd_makenoise , command_count }; // define pointer function within class takes // int argument typedef void(animal::*animalfunc)(int); // u thing problem - can templated? if so, not figure out syntax make work struct commandinfo { unsigned int code; animalfunc handler; char const* name; }; animal(char const* name) : _name(name) { registercommands(); } // register commands supported class virtual void registercommands() { #if tracing serial.print(f("registering ")); serial.print(getname()); serial.println(f(" actions:")); #endif unsigned int index = 0; registercommand(index++, cmd_eat, "eat", &animal::eat); registercommand(index++, cmd_sleep, "sleep", &animal::sleep); registercommand(index++, cmd_makenoise, "make noise", &animal::makenoise); assert(index == 3); } // register using index rather code don't overload meaning of code. void registercommand(unsigned int index, unsigned int code, char const* action, animalfunc fn) { assert(code < command_count); _commands[index].code = code; _commands[index].name = action; _commands[index].handler = fn; #if tracing serial.print( "registering: index="); serial.print(index); serial.print(f(", code=")); serial.print(_commands[index].code); serial.print(f(", action=")); serial.println(_commands[index].name); #endif } void report(unsigned int code, char const* msg) { commandinfo info = getcommandinfo(code); #if tracing serial.print(msg); serial.print(info.code); serial.print(" ["); serial.print(info.name); serial.println("]"); #endif } void exec(int code, int value) { commandinfo info = getcommandinfo(code); #if tracing report(code, "executing: "); #endif (this->*info.handler)(value); } char const* getname() { return _name; } // base class methods virtual void eat(int times) { while (times-- > 0) { reportdofunc(cmd_eat); } } virtual void sleep(int times) { while (times-- > 0) { reportdofunc(cmd_sleep); } } virtual void makenoise(int times) { while (times-- > 0) { reportdofunc(cmd_makenoise); } } virtual void showactions() { #if tracing serial.print(getname()); serial.print(f(" implements ")); serial.print(command_count); serial.println(f(" actions:")); (int = 0; < command_count; i++) { showaction(i); } #endif } void showaction(unsigned int index) { #if tracing serial.print(f("index: [")); serial.print(index); serial.print(f("] code: [")); serial.print(_commands[index].code); serial.print(f("] ")); serial.println(_commands[index].name); #endif } private: char const* _name; // define array of pointers action functions commandinfo _commands[command_count]; // return command associated code commandinfo getcommandinfo(unsigned int code) { #if tracing serial.print(f("in getcommandinfo: code=")); serial.print(code); serial.println(f(":")); #endif (int = 0; < command_count; i++) { #if tracing serial.print(f("checking index: [")); serial.print(i); serial.print(f("], code: [")); serial.print(_commands[i].code); #endif if (code == _commands[i].code) { #if tracing serial.print(f("] found ")); serial.println(_commands[i].name); #endif return _commands[i]; } #if tracing serial.println("]"); #endif } // invalid command code object assert(false); } void reportdofunc(unsigned int code) { commandinfo info = getcommandinfo(code); #if tracing serial.print(code); serial.print(f(": ")); serial.println(info.name); #endif } }; //class mammal : public animal { <-- form fails: "no matching function call animal::animal() class mammal { public: enum { cmd_births_baby = 1, command_count }; typedef void(mammal::*mammalfunc)(int); // <-- difference animalfunc class name struct commandinfo { unsigned int code; char const* name; mammalfunc handler; // <-- difference parent class mammalfunc }; // constructor mammal(char const* name) : _name(name) { // <-- identical parent (animal) class registercommands(); } // register commands supported class virtual void registercommands() { #if tracing serial.print(f("registering ")); serial.print(getname()); serial.println(f(" actions:")); #endif // can list abstracted table register command can inherit? unsigned int index = 0; registercommand(index++, cmd_births_baby, "births baby", &mammal::birthsbaby); } // difference animal::registercommand last argument (mannalfunc instead of animalfunc) void registercommand(unsigned int index, unsigned int code, char const* action, mammalfunc fn) { // assure don't have more commands thought... assert(index < command_count); // update values of current placeholder struct's values _commands[index].code = code; _commands[index].name = action; _commands[index].handler = fn; #if tracing report(code, "registering: "); #endif } // identical animal::exec void exec(int code, int value) { commandinfo info = getcommandinfo(code); #if tracing report(code, "executing: "); #endif (this->*info.handler)(value); } // identical animal::report void report(unsigned int code, char const* msg) { commandinfo info = getcommandinfo(code); #if tracing serial.print(msg); serial.print(info.code); serial.print(" ["); serial.print(info.name); serial.println("]"); #endif } // identical animal::getname char const* getname() { return _name; } // identical animal::showactions virtual void showactions() { #if tracing serial.print(getname()); serial.print(f(" implements ")); serial.print(command_count); serial.println(f(" actions:")); (int = 0; < command_count; i++) { showaction(i); } #endif } // identical animal::showaction void showaction(unsigned int index) { assert(index < command_count); #if tracing serial.print(f("[")); serial.print(_commands[index].code); serial.print(f("] ")); serial.println(_commands[index].name); #endif } // concrete action virtual void birthsbaby(int times) { while (times-- > 0) { reportdofunc(cmd_births_baby); } } private: // inherit? char const* _name; // commandinfo mammal-specific. can generic? // define array of pointers action functions commandinfo _commands[command_count]; commandinfo getcommandinfo(unsigned int code) { #if tracing serial.print(f("in getcommandinfo: code=")); serial.print(code); serial.println(f(":")); #endif (int = 0; < command_count; i++) { #if tracing serial.print(f("checking index: [")); serial.print(i); serial.print(f("], code: [")); serial.print(_commands[i].code); #endif if (code == _commands[i].code) { #if tracing serial.print(f("] found ")); serial.println(_commands[i].name); #endif return _commands[i]; } #if tracing serial.println(f("]")); #endif } // invalid command code object assert(false); } // identical animal::reportdofunc void reportdofunc(unsigned int code) { commandinfo info = getcommandinfo(code); #if tracing serial.print(code); serial.print(f(": ")); serial.println(info.name); #endif } }; int main() { animal *panimal = new animal("animal"); panimal->exec(animal::cmd_eat, 1); panimal->exec(animal::cmd_sleep, 1); panimal->exec(animal::cmd_makenoise, 2); panimal->showactions(); mammal* pmammal = new mammal("mammal"); pmammal->exec(mammal::cmd_births_baby, 2); pmammal->showactions(); pmammal->exec(animal::cmd_eat, 2); delete pmammal; delete panimal; }
Comments
Post a Comment