简体   繁体   中英

Java design, calling the associated business logic/service

I have 3 objects, a DTO called BalanceDTO which implements a interface RequestDTO and a Balance Entity. I created the DTO because the entity I can't use, JAXB compliance (legacy code).

The DTO is used in the web service layer, BalanceService , and the Entity in the API I integrate to from the web service. Between the web service and the API there is validation. RequestValidation which has sub validations for each type of RequestDTO ie BalanceRequestValidation .

The validation component takes in a RequestDTO as a parameter and then needs to do validation for the specific component. At the point of input the validation component doesn't know which object has been passed to it ie BalanceDTO , it only sees the interface.

I want to avoid using instanceof so I was thinking of using a visitor on the DTO so that it delegates itself to the validation that needs to be performed on it.

But the validation needs more/other components as well not just the BalanceDTO as input parameters and different validations needs different input params.

Is there another way to know which object you are working with and the validation to choose without using instanceof? Another design that I can follow?

You are well on the right track here - the Visitor design pattern is often the best way to avoid downcasting.

I am going to suggest a combination of the visitor and delegation design patterns, though let's walk through some alternatives.

Having the object do the validation itself via the RequestDTO interface is not viable since you need different components and the validation is not trivial in nature.

Using instanceof and downcasting looks a little messy, and the compiler won't complain if you add a new validatable class and forget to add the validator - you'll be relying on a runtime error via ...else { throw new IllegalArgumentException("Unknown RequestDTO subtype!"); } ...else { throw new IllegalArgumentException("Unknown RequestDTO subtype!"); }

The visitor design pattern is the classic way to avoid downcasting plus it also gives you a compiler error if you add a new class that should be validatable and forget to add the validation.

You can use accept() and visit() methods, or you can use method naming that is closer to your domain, eg validate() , like this:

public interface RequestDTO {
    boolean validate(RequestValidation validator);
}

public class BalanceDTO implements RequestDTO {
    // ...

    @Override
    public boolean validate(RequestValidation validator) {
        return validator.validate(this);
    }
}

public class RequestValidation {
    // components...

    public boolean validate(BalanceDTO balanceDTO) {
        return true;    // todo...
    }

    public boolean validate(AnotherDTO anotherDTO) {
        return true;    // todo...
    }
}

If you want to go a bit further you can delegate the validation to specific validation components, like this:

public class RequestValidation {
    BalanceRequestValidation balanceRequestValidation;
    AnotherRequestValidation anotherRequestValidation;

    public boolean validate(BalanceDTO balanceDTO) {
        return balanceRequestValidation.validate(balanceDTO, a, b, c);
    }

    public boolean validate(AnotherDTO anotherDTO) {
        return anotherRequestValidation.validate(anotherDTO, x, y, z);
    }
}

Given I have understood your problem correctly, the visitor design pattern, possibly combined with the delegation design pattern, is indeed a good approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM