MarcosTonina
MarcosTonina

Reputation: 361

Code repetition vs readablility

I have multiple services (in Spring MVC) that are children of a global Service. So I need to know about the best practice (or your opinions) with multiple methods with this example:

//Domain classes
public class MyParentObject{}
public class MyObj extends MyParentObject{}

//Services
public class MyParentObjectServiceImpl implements MyParentObjectService{

  @Override
  public MyParentObject findObjectByProp(String prop, String objectType){
      //myCode (not abstract class)
    }

}

public class MyObjServiceImpl extends MyParentObjectServiceImpl implements MyObjectService{

  private myObjType = "MyObj";

  @Override
  public MyObj findMyObjByProp(String prop){

   return (MyObj) super.findObjectByProp(prop, this.myObjType); 

  }
}

And in this approach, I use calls like this:

MyObj foo = myObjService.findMyObjByProp(prop);

So I need to know if this approach is "better" or more apropiate that calling directly the parent method with the second parameter. E.g:

MyObj foo = (MyObj)myParentObjectService.findObjectByProp(prop, "MyObj");

..and avoiding the creation of second methods, more specific. It is important to know that the children services will be created anyway, because we have lot of code that is specific of a domain objects.

I have the idea that the first approach is better, because is more readable, but I need to support that decision with some documents, blog, or opinions to discuss this designs with my colleagues.

Upvotes: 1

Views: 123

Answers (1)

Giovanni Botta
Giovanni Botta

Reputation: 9816

This looks like a tagged class hierarchy. It's difficult to comment on the value of this design in general without knowing the details. However, a slightly different approach that I would recommend is to generify your base class to gain a little bit of type safety.

In particular:

public /* abstract */ class MyParentObjectServiceImpl<T extends MyParentObject>
  implements MyParentObjectService{

  MyParentObjectServiceImpl(Class<T> type) { this.type = type; }

  private final Class<T> type; // subclasses provide this

  @Override
  public T findObjectByProp(String prop){
    //you can use type for object specific stuff
  }
}

public class MyObjServiceImpl extends MyParentObjectServiceImpl<MyObj>
  // You might not need this interface anymore 
  // if the only method defined is findMyObjByProp
  /* implements MyObjectService */ {
  MyObjServiceImpl() {
    super(MyObj.class);
  }

  @Override
  public /* final */ MyObj findMyObjByProp(String prop) {
    return (MyObj) super.findObjectByProp(prop, this.myObjType);
  }
}

You definitely gain in type safety (casting will only appear in the base class), you get rid of the "tags" (the strings that identify the different objects) and possibly reduce the number of classes/interfaces required to implement the whole hierarchy. I successfully used this approach several times. Note that this works best if the base class is abstract. Food for thoughts.

Upvotes: 3

Related Questions