Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate code refactoring in Java with patterns

This is more about Java than Dropwizard; but I have two resources in Dropwizard: CustomerResource and ApiResource.

In CustomerResource there is a createCustomer method which basically creates a new customer. The ApiResource will also create a new customer when a third party invokes a method inside of it, so this got me thinking about duplicate code and the best way to resolve it. I have a few approaches in mind; but first here are the classes for better clarity.

@Path("/internal")        
public class CustomerResource{
    private DBDao dbDao;
    private AnotherAPI api;

    //constructor for DI

    public Response Create(@internalAuth CustomerPojo customerPojo) {
        //logic to validate customerpojo
        //logic to ensure user isn't a duplicate
        //some other validation logic
        //finally user creation/saving to DB
        Return response.ok(200).build();
    }
}

@Path("/external")
public class ApiResource{
    private DBDao dbDao;
    private AnotherAPI api;

    //constructor for DI

    public Response Create(@ExternalAuth PartialCustomerPojo partialCustomerPojo) {
        //logic to validate PartialCustomerpojo
        //supplement partialCustomerPojo
        //logic to ensure user isn't a duplicate
        //some other validation logic
        //finally user creation/saving to DB
        Return response.ok(200).build();
    }
}

So two main differences are how the endpoint is called (authentication) and the payload provided.

The way I thought about removing duplicate code is to create a new concrete class that takes commonality from both resources and each of them instantiates a new class like this.

public class CommonClass{
    private DBDao dbDao;
    private AnotherAPI api;

    //constructor for DI

    public boolean Create (CommonPojo commonPojo) {
        //logic to validate customerPojo
        //logic to ensure user isn't a duplicate
        //some other validation logic
        //finally user creation/saving to DB
        Return response.ok(200).build();
    }
}

And now inside CustomerResource and ApiResource I simply do this.

CommonClass commonClass = new CommonClass(dbDao, api);
//create a new instance customerPojo or CommonPojo and call 

commonClass.create(customerPojo);

Does this sound like a good strategy? Are there other concerns beyond duplication? These two resource methods can't be inside the same class either. Any best practice will be appreciated.

like image 619
RethinkStrategy Avatar asked May 13 '26 05:05

RethinkStrategy


1 Answers

I think inheritance not the best solution. Also I think that composition is much better. This can help you to use common code and easy to change it in other places where you need to change functionality.

Also it allows you to test all classes more easy.

For example:

class CommonPojo {}
class CustomerPojo extends CommonPojo {}
class PartialCustomerPojo extends CommonPojo {}

interface IResourceValid {
    boolean isResourceValid(CommonPojo pojo);
}

class CustomerPojoValidator implements IResourceValid {
    @Override
    public boolean isResourceValid(CommonPojo pojo) {
        //your validation for customer
        return false;
    }
}

class PartialCustomerPojoValidator implements IResourceValid {
    @Override
    public boolean isResourceValid(CommonPojo pojo) {
        //your validation for partial customer
        return true;
    }
}

class CommonResource{
    private DBDao dbDao;
    private AnotherAPI api;
    private IResourceValid validator;

    public IResourceValid getValidator() {
        return validator;
    }

    //constructor for DI

    public Response Create(CommonPojo commonPojo) {
        //logic to validate customerpojo
        //logic to ensure user isn't a duplicate
        //some other validation logic
        //finally user creation/saving to DB
        validator.isResourceValid(commonPojo);
        return response.ok(200).build();
    }
}

//@Path("/internal")
class CustomerResource{
    private CommonResource resource;

    //constructor for DI

    public Response Create(CustomerPojo CustomerPojo) {
        return resource.Create(CustomerPojo);
    }
}

//@Path("/external")
class ApiResource{
    private CommonResource resource;

    //constructor for DI

    public Response Create(PartialCustomerPojo partialCustomerPojo) {
        return resource.Create(partialCustomerPojo);
    }
}

DBDao dao = new DBDao();
AnotherAPI api = new AnotherAPI();

CommonResource castomerCreator = new CommonResource(new CustomerPojoValidator(), dao, api);
CommonResource apiCreator = new CommonResource(new PartialCustomerPojoValidator(), dao, api);

CustomerResource customerResource = new CustomerResource(castomerCreator);
ApiResource apiResource = new ApiResource(apiCreator);

customerResource.Create(somePojo);
apiResource.Create(someAnotherPojo);
like image 156
no_fate Avatar answered May 14 '26 18:05

no_fate