Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class structure pattern question. What should I choose?

Tags:

class-design

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.

like image 923
Paralife Avatar asked Sep 26 '08 09:09

Paralife


5 Answers

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.
like image 59
scubabbl Avatar answered Jan 02 '23 21:01

scubabbl


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

like image 33
Garth Gilmour Avatar answered Jan 02 '23 21:01

Garth Gilmour


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.
like image 21
Andy Balaam Avatar answered Jan 02 '23 20:01

Andy Balaam


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.

like image 30
Jon Limjap Avatar answered Jan 02 '23 19:01

Jon Limjap


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

like image 36
Thorsten79 Avatar answered Jan 02 '23 21:01

Thorsten79