使用模式在Java中重复代码重构

问题描述 投票:3回答:4

这更像是关于Java而不是Dropwizard;但我在Dropwizard有两个资源:CustomerResourceApiResource

CustomerResource有一个createCustomer方法,基本上创造了一个新的客户。当第三方调用其中的方法时,ApiResource也会创建一个新客户,这让我想到了重复的代码和解决它的最佳方法。我有几个方法;但首先是这些类以便更清晰。

@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();
    }
}

因此,两个主要区别在于如何调用端点(身份验证)和提供的有效负载。

我想要删除重复代码的方法是创建一个新的具体类,它从两个资源中获取通用性,并且每个类都实例化一个这样的新类。

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();
    }
}

现在在CustomerResourceApiResource内部,我只是这样做。

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

commonClass.create(customerPojo);

这听起来像是一个好策略吗?除了重复之外还有其他问题吗?这两种资源方法也不能在同一个类中。任何最佳实践将不胜感激。

java design-patterns refactoring dropwizard
4个回答
2
投票

我认为继承不是最好的解决方案。我认为组成要好得多。这可以帮助您使用通用代码,并在您需要更改功能的其他位置轻松更改它。

它还允许您更轻松地测试所有类。

例如:

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);

1
投票

有很多选择,这取决于您使用的策略。我更喜欢使用抽象类并在其中创建非抽象方法。扩展抽象类时,选择要使用的方法。在您的方案中,它应该看起来像这样:

public abstract class AbstractResource {

    private CustomerService customerService;

    @Autowired
    public void setCustomerService(CustomerService customerService) {
        this.customerService = customerService;
    }

    public Response create(CustomerPojo customer) {
        return customerService.createCustomerPojo(customer);
    }

    public Response create(PartialCustomerPojo customer) {
        return customerService.createPartialCustomerPojo(customer);
    }

}

CustomerResource @Override只需要以下方法:

@Path("/internal")
@Component
public class CustomerResource extends AbstractResource {

    @POST
    @Override
    public Response create(PartialCustomerPojo customer) {
        return super.create(customer);
    }

}

同样的ApiResource

@Path("/external")
@Component
public class ApiResource extends AbstractResource {

    @POST
    @Override
    public Response create(CustomerPojo customer) {
        return super.create(customer);
    }

}

一切都在一个地方 - qazxsw poi,你在那里做你的逻辑。

CustomerService

如果要最小化重复,则必须使用接口并在每个类中实现:

@Service
public class CustomerService {

    @Autowired
    private AnotherAPI api;

    @Autowired
    private DBDao dao;

    public Response createCustomerPojo(CustomerPojo customer) {
        //logic to validate customerpojo
        //logic to ensure user isn't a duplicate
        //some other validation logic
        //finally user creation/saving to DB
    }

    public Response createPartialCustomerPojo(PartialCustomerPojo customer) {
        //logic to validate PartialCustomerpojo
        //supplement partialCustomerPojo
        //logic to ensure user isn't a duplicate
        //some other validation logic
        //finally user creation/saving to DB
    }
}

现在你只能有一个抽象方法:

public class CustomerPojo implements PojoInterface {
}
public class PartialCustomerPojo implements PojoInterface {
}

然后在'一个地方'你需要检查每个参数的实例:

public abstract class AbstractResource {

    private CustomerService customerService;

    @Autowired
    public void setCustomerService(CustomerService customerService) {
        this.customerService = customerService;
    }

    public abstract Response create(PojoInterface customer);

}

编辑:对不起,很长的帖子......


1
投票

这可以通过以下两种方式实现

  1. 创建一个接口,然后在两个目标类上实现,这样它们都可以提供本地实现
  2. 使用抽象类然后扩展它。

接口不会使您免于编码,但保留内联的内容,抽象类不强制执行任何操作,因此两者都有缺陷。您可以实现多个接口,但只能扩展一个类。记住这一点我更倾向于接口

从Java 8. Java支持使用接口的默认方法,这是我认为最好的方法。您可以在默认方法中提供默认实现,用户可以根据需要覆盖该方法。这将为您提供最佳的Interface和Abstract类。

public Response create(PojoInterface customer) {
        if (customer instanceof CustomerPojo){
            //logic to validate customerpojo
            //logic to ensure user isn't a duplicate
            //some other validation logic
            //finally user creation/saving to DB
        }else if (customer instanceof 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
        }
    }

0
投票

创建一个接口,让两个类实现它。在接口和子类之间添加一个抽象基类调用,并将任何公共代码重构到其中。

© www.soinside.com 2019 - 2024. All rights reserved.