Cycle Abstraction Pattern

Context:

Forces: Therefore:

If the cycle has length greater than 2 or if it links two libraries/components:

The last two are usually useful only when the cycle wasn't actually needed in the problem domain, but just happened in the solution.

Example:


// With Cycle:

 class Hornhair
 { 
  // ...
  private: set<Drone> dronesM;
 };

class Drone { // ... private: set<Task> tasksM; };

class Task { // ... private: Hornhair * supervisorM; };


// Abstract A Base Class:

 class Hornhair: public Manager
 { 
  // ...
  private: set<Drone> dronesM;
 };

class Drone { // ... private: set<Task> tasksM; };

class Task { // ... private: Manager * supervisorM; };


// Shift Responsibility:

 class Hornhair
 { 
  // ...
  private: set<Drone> dronesM;
 };

class Drone { // ... private: set<Task> tasksM; private: Hornhair * supervisorM; };

class Task { // ... };


// Use AssociationClass:

 class Hornhair
 { 
  // ...
  private: Team  teamM;
 };

class Team: public multimap<Drone *, Task *> { // ... };

class Drone { // ... };

class Task { // ... };


See Also:


It is [sort of] possible to tell what the prescription of this pattern is. It is not possible for this reader to see why this pattern is. To exhibit this it would be necessary to show two programs of identical functionality, one the first way, one the second, and to show that the second is more maintainable or more understandable or better on some dimension. -- RonJeffries


I wonder when would the second or third tactic be needed if you have the first one (extract-superclass)? I think I'm missing something about the cyclical refactoring that you mentioned. -- MichaelFeathers


Okay folks, keep your hats on, there's more code coming here. I'm not certain that showing changes communicating around this 3-cycle will actually make my point, but it's certainly a worthwhile exercise if nothing else. -- PeterMerel


This stuff seems related to what Robert C. Martin calls the DependencyInversionPrinciple. He says that stable things should not depend on unstable things. He makes the unstable more stable by making a more abstract version of it: a new base class. Then both the original dependant and the concrete unstable thing itself depend on the abstraction. The "dependency arrow" from the unstable thing reverses direction.

His solution is thus similar to your "Abstract a base class". What about the problems they solve? What I'm struggling with here is why you say it is cycles, specifically, which are bad. I think it's a special case. If the cycle contains a mixture of stable and unstable things, then necessarily at least one of the stable things must be depending on an unstable thing.

Otherwise it just seems like an example of the general principle that dependencies are bad and abstractions good. -- DaveHarris


CategoryAbstraction


EditText of this page (last edited June 18, 2006) or FindPage with title or text search