jheppinstall
jheppinstall

Reputation: 2358

Object Oriented Method Design options

I want to develop a process() method. The method takes some data in the form of a data class, and processes it. The data classes are similar, but slightly different.

For example we have the following classes of data processDataObject_A, processDataObject_B and processDataObject_C.

Is it better to overload the method:

void process(processDataObject_A data)
{
//Process processDataObject_A here
}

void process(processDataObject_B data)
{
//Process processDataObject_B here
}

void process(processDataObject_C data)
{
//Process processDataObject_C here
}

OR have the concrete data classes extend some Abstract Data Class, and pass that to the process method and then have the method check the type and act accordingly:

void process(AbstractProcessDataObject data)
{
//Check for type here and do something  
}

OR is there some better way to address it? Would the approach change if this were to be a Web Method?

Thanks in advance

Upvotes: 1

Views: 403

Answers (5)

Pablo Retyk
Pablo Retyk

Reputation: 5750

I believe the Strategy pattern would help you.

Upvotes: 0

toshi
toshi

Reputation: 51

I second Marko's design. Imagine you need to add another type of data structure and process logic, say processDataObject_D. With your first proposed solution (method overloading), you will have to modify the class by adding another method. With your second proposed solution, you will have to add another condition to the type checking and execution statement. Both requires you to modify the existing code. Marko's solution is to avoid modifying the existing code by leveraging polymorphism. You don't have to code if-else type checking. It allows you to add new data structure and process logic without modifying the existing code as long as the new class inherits the same super class.

Studying Strategy Pattern of the design patterns will give you full theoritical understanding of the problem you are facing. The book "Head First Design Pattern" from O'Reilly is the best introduction I know of.

Upvotes: 1

tvanfosson
tvanfosson

Reputation: 532435

The fact that your methods return void lead me to believe that you may have your responsibilities turned around. I think it may be better to think about this as having each of your classes implement an interface, IProcessable, that defines a Process method. Then each class would know how to manipulate it's own data. This, I think, is less coupled than having a class which manipulates data inside each object. Assuming all of theses classes derive from the same base class you could put the pieces of the processing algorithm that are shared in the base class.

This is slightly different than the case where you may have multiple algorithms that operate on identical data. If you need this sort of functionality then you may still want to implement the interface, but have the Process method take a strategy type parameter and use a factory to create an appropriate strategy based on its type. You'd end up having a strategy class for each supported algorithm and data class pair this way, but you'd be able keep the code decoupled. I'd probably only do this if the algorithms were reasonably complex so that separating the code makes it more readable. If it's just a few lines that are different, using the switch statement on the strategy type would probably suffice.

With regard to web methods, I think I'd have a different signature per class. Getting the data across the wire correctly will be much easier if the methods take concrete classes of the individual types so it knows how to serialize/deserialize it properly. Of course, on the back end the web methods could use the approach described above.

public interface IProcessable
{
    public void Process() {....}
}

public abstract class ProcessableBase : IProcessable
{
    public virtual void Process()
    {
        ... standard processing code...
    }
}

public class FooProcessable : ProcessableBase
{
    public override void Process()
    {
        base.Process();
        ... specific processing code
    }
}

...

IProcessable foo = new FooProcessable();
foo.Process();

Implementing the strategy-based mechanism is a little more complex.

Web interface, using data access objects

[WebService]
public class ProcessingWebService
{
    public void ProcessFoo( FooDataObject foo )
    {
        // you'd need a constructor to convert the DAO
        // to a Processable object.
        IProcessable fooProc = new FooProcessable( foo );
        fooProc.Process();
    }

}

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1062630

How about polymorphism on AbstractProcessDataObject - i.e. a virtual method? If this isn't appropriate (separation of concerns etc), then the overload would seem preferable.

Re web-methods; very different: neither polymorphism nor overloading are very well supported (at least, not on basic-profile). The detection option "Check for type here and do something" might be the best route. Or have different named methods for each type.


per request:

abstract class SomeBase { // think: AbstractProcessDataObject
    public abstract void Process();
}
class Foo : SomeBase {
    public override void Process() { /* do A */ }
}
class Bar : SomeBase {
    public override void Process() { /* do B */ }
}
SomeBase obj = new Foo();
obj.Process();

Upvotes: 0

Marko
Marko

Reputation: 31375

I would go with:

process (data) {
   data.doProcessing();
}

Upvotes: 8

Related Questions