Paralife
Paralife

Reputation: 6236

Class structure pattern question. What should I choose?

What are (if any)the implied assumptions or restrictions and the differences of designing like:

A) this:

class SampleClass1
{
    IWorker workerA;
    IWorker workerB;

    void setWorkerA(IWorker w);
    void setWorkerB(IWorker w);
    WorkResult doWork();
}

B) versus this:

class SampleClass2
{
    WorkResult doWork(IWorker workerA, IWorker workerB);
}

I know it depends on the specific project but what if the above class is a part of a small framework? The first Class is able to maintain state and separate the steps more naturaly but Second class ensures "real time communication" with the external caller more naturaly since Worker are passed each time doWork() is called.

Are there any recommended usages or generic practices that guide the choice between the two above ways? Thanks.

Upvotes: 6

Views: 600

Answers (8)

Andy Balaam
Andy Balaam

Reputation: 6671

Another option, a variant of case A, is the following:

class SampleClass3
{
    SampleClass3( IWorker workerA, IWorker workerB );
    WorkResult doWork();
}

Advantages:

  • It's harder to make the object defective, since you are required to supply all the workers that are needed at construction time (in contrast to case A).

  • You can still carry state inside SampleClass3 and/or one of the workers. (This is impossible in case B.)

Disadvantages:

  • You have to have all your workers ready before you construct SampleClass3, instead of being able to provide them later. Of course, you could also provide the setters, so that they can be changed later.

Upvotes: 2

Garth Gilmour
Garth Gilmour

Reputation: 11284

In option (A) you are creating what is known as a Function Object or Functor, this is a design pattern that is well documented.

The two main advantages are:

  • The workers can be set by in one place and then the object used elsewhere
  • The object can retain state between calls

Also if you are using a dependency injection framework (Spring, Guice etc...) the functor can be automatically initialized and injected wherever required.

Function objects are extensively used in libraries e.g. the C++ Standard Template Library

Upvotes: 5

scubabbl
scubabbl

Reputation: 12827

SampleClass1

  • I may need to maintain state of the workers between doWork
  • I might need the capability to set Workers individually. (doWork with 1 and 2, then with 2 and 3)
  • I want to maintain the workers because it might be expected to run doWork multiple times on the same workers.
  • I'm not a utility class. An instance of me is important.

SampleClass2

  • Give me two workers and I will do work with them.
  • I don't care who they are and I don't want to maintain them.
  • It's someone else's job to maintain any pairing between workers.
  • I may be more of a utility class. Maybe I can just be static.

Upvotes: 6

Konrad Rudolph
Konrad Rudolph

Reputation: 546113

How about instead defining a WorkDelegate (or alternatively an interface having a single doWork method without argument) that simply returns a WorkResult and letting individual classes decide how they implement it? This way, you don't confine yourself to premature decisions.

Upvotes: 0

aku
aku

Reputation: 124044

IMO 2nd approach looks better, it requires caller to use less code to perform a task. 2nd approach is less error prone, caller don't need to worry that object might be not initialized completely.

Upvotes: 0

Thorsten79
Thorsten79

Reputation: 10128

A) is a bad design because it allows the object to be defective (one or both of the worker classes might not have been set).

B) can be good. Make it static though if you do not depend on the internal state of SampleClass2

Upvotes: 1

Jon Limjap
Jon Limjap

Reputation: 95502

If more than one method depends on IWorker a and IWorker b, I say do sample A.

If only doWork() uses both IWorker a and IWorker b, then do sample B.

Also, what is the real purpose of your SampleClass? doWork looks a bit like a utility method mroe than anything else.

Upvotes: 1

Richard Walton
Richard Walton

Reputation: 4785

Another Option:

IWorker class:

static WorkResult doWork(Iworker a, Iworker b);

Upvotes: 0

Related Questions