Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用模式在Java中进行重复代码重构_Java_Design Patterns_Refactoring_Dropwizard - Fatal编程技术网

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

使用模式在Java中进行重复代码重构,java,design-patterns,refactoring,dropwizard,Java,Design Patterns,Refactoring,Dropwizard,这更多的是关于Java而不是Dropwizard;但是我在Dropwizard中有两个资源:CustomerResource和ApiResource 在CustomerResource中有一个createCustomer方法,它基本上创建了一个新客户。当第三方调用ApiResource中的方法时,ApiResource也会创建一个新客户,所以这让我想到了重复代码以及解决它的最佳方法。我有一些想法;但是,为了更清晰,这里首先介绍了一些课程 @Path("/internal") pu

这更多的是关于Java而不是Dropwizard;但是我在Dropwizard中有两个资源:
CustomerResource
ApiResource

CustomerResource
中有一个
createCustomer
方法,它基本上创建了一个新客户。当第三方调用ApiResource中的方法时,
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();
    }
}
现在在
CustomerResource
ApiResource
中,我只需这样做

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

commonClass.create(customerPojo);

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

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

有很多选项,这取决于您使用的策略。我更喜欢使用抽象类并在其中创建非抽象方法。扩展抽象类时,您可以选择要使用的方法。 在您的场景中,它应该如下所示:

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
@仅覆盖需要:

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

}
一切都在onle place-
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);

}
然后在“一个地方”中,您需要检查参数的每个实例:

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
        }
    }

编辑:很抱歉发了这么长的帖子…

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

  • 创建一个接口,然后在两个目标类上实现,这样它们都可以提供本地实现

  • 使用抽象类,然后扩展它

  • 接口并没有使您免于编写代码,而是将内容内联,因为抽象类不强制执行任何内容,所以两者都有弱点。您可以实现多个接口,但只能扩展一个类。记住这一点,我更倾向于界面

    从Java8开始。Java支持使用接口的默认方法,我认为这是最好的方法。您可以在默认方法中提供默认实现,如果用户愿意,可以重写该方法。这将为您提供最佳的接口和抽象类

    public interface CommonCode {
    
        default 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();
        }
    }
    
    @Path("/internal")        
    public class CustomerResource  implements CommonCode {
        private DBDao dbDao;
        private AnotherAPI api;
    
        //constructor for DI
        create(CommonPojo)
    }
    
    @Path("/external")
    public class ApiResource implements CommonCode {
        private DBDao dbDao;
        private AnotherAPI api;
    
        //constructor for DI
        create(CommonPojo)
    }
    

    我认为继承不是最好的解决办法。 而且我认为作文要好多了。这可以帮助您使用通用代码,并在需要更改功能的其他地方方便地进行更改

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

    例如:

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

    谢谢不过有点困惑。你能给我看一个框架吗?你在使用委托,我建议你使用继承。你可能不应该从
    CommonClass
    返回HTTP特定的代码/对象。您应该返回创建响应对象,或引发异常。然后,
    *资源
    类应该负责解释来自
    CommonClass
    的响应,并将其转换为正确的HTTPresponse@DanielScott同意。好电话。我通常不这么做。我没有直接把问题打出来。非常感谢你的详细解释。这很有道理。使用带有默认方法的接口似乎是两全其美。谢谢你的建议。@很高兴我能帮上忙:)对于继承,每个方法都需要提供自己的实现,因此不能减少重复代码,除非你选择java 1.8中的默认方法,如前面的答案中所建议的那样。同意组合方法和关于测试的重要观点。谢谢你的详细回答和解释。