c++ - Pattern for choosing behaviour based on the types present in a collection derived objects -
i have collection of objects represents model of system. each of these objects derives base class represents abstract "component". able @ system , choose behaviours based on components present , in order.
for sake of argument, let's call base class component
, actual components inputfilter
, outputfilter
, processor
. systems can deal ones processor
, 1 or both filters. actual system has more types , more complex interaction between them, think now.
i can see 2 "simple" ways handle situation marshalcomponentsettings()
function takes 1 of collections , works out how efficiently set each node. may require modifying inputs in ways or splitting them differently, it's not quite simple implementing virtual handlesettings()
function per component.
the first report enumerated type each class using pure virtual function , use work out do,
dynamic_cast
'ing needed access component specific options.enum comptype { input_filter, output_filter, processor } void marshal(settings& stg) { if (comps[0].type() == input_filter) setupinputfilter(stg); //maybe modified stg, or provides other feedback of done // similar outputs setupprocessor(stg); }
the second
dynamic_cast
might option in function , use success of or not (as maybe cast object if needed) determine do.void marshal(settings& stg) { if (inputfilter* filter = dynamic_cast<inputfilter*>(comp[0])) setupinputfilter(stg); //maybe modified stg, or provides other feedback of done // similar outputs setupprocessor(stg); }
it seems first efficient way (don't need speculatively test each object find out is), doesn't quite seem right (maybe due annoying details of how devices affect each other leaking general marshaling code).
is there more elegant way handle situation nest of conditionals determining behaviour? or name situation or pattern?
your scenario seems ideal candidate visitor design pattern, following roles (see uml schema in link):
- objectstructure: model, aka collection of
component
- element:
component
base class - concreteelementx: actual components (
inputfilter
,outputfilter
,processor
, ...) - visitor: abstract family of algorithms has manage model consistent set of elements.
- concretevisitora: configuration process.
main advantages:
your configuration/set-up corresponds design pattern's intent: an operation performed on elements of object structure. conversely, pattern allows take consideration order , kind of elements encountered during traversal, visitors can stateful.
one positive side effect visitor pattern give desing flexibility add new processes/algortihms similar traversals different purpose (for example: pricing of system, material planning, etc...)
class visitor; class component { public: virtual void accept(class visitor &v) = 0; }; class inputfilter: public component { public: void accept(visitor &v) override; // calls right visitor function }; ... class visitor { public: virtual void visit(inputfilters *c) = 0; // 1 virtual funct each derived component. virtual void visit(processor *c) = 0; ... }; void inputfilter::accept(visitor &v) { v.visit(this); } ... class setup : public visitor { private: bool hasprocessor; int impedencefilter; int circuitresistance; public: void visit(inputfilters *c) override; void visit(processor *c) override; ... };
challenge:
the main challenge you'll have visitor, other alternatives well, setup can change configuration (replacing component ? change of order), have take care of keeping consitent iterator on container while making sure not process items several time.
the best approach depends on type of container, , on kind of changes setup doing. you'll need flags see element processed, or temporary container (either elements processed or elements remaining processed).
in case, visitor class, can encapsulate such state data in private members.
Comments
Post a Comment