繁体   English   中英

用多态替换switch-case

[英]Replace switch-case with polymorphism

我知道已经有类似的问题,但看着它们我仍然对如何设计我的代码有一些疑问。 我有一个允许User 注册/登录/更新/删除的服务 问题是User是一个抽象类型,它包含数据typeOfUser基于该类型应该调用实际的注册/更新/删除方法,现在我在switch-case块中执行此操作。 我想用更好的设计取代它。

UserController.java

public class UserController {

    public UserDto register(UserDto user) {
        switch(user.getTypeOfUser()) {
        case DRIVER: return driverService.register(user);
        case CUSTOMER: return customerService.register(user);
        // ...
        }
    } 

    public UserDto update(UserDto user) {
        switch(user.getTypeOfUser) {
        case DRIVER: return driverService.update((DriverDto) user);
        case CUSTOMER: return customerService.update((CustomerDto) user);
        // ...
        }
    }

    public UserDto login(long userId) {
        loginService.login(userId);

        UserBO user = userService.readById(userId);

        switch(user.getTypeOfUser) {
        case DRIVER: return DriverDto.fromBO((DriverBO) user);
        case CUSTOMER: return CustomerDto.fromBO((CustomerBO) user);
        // ...
        }
    }

    // ...
}

我知道可以使用像Visitor模式这样的东西,但我真的需要在Enum本身添加注册/登录/更新/删除方法吗? 我真的不知道如何做到这一点,任何帮助表示赞赏。

我想用更好的设计取代它。

替换switch语句并利用Polymorphism的第一步是确保每个操作都有一个单一的合同(读取方法签名),而不管用户类型如何。 以下步骤将说明如何实现此目的:

步骤1:定义执行所有操作的通用接口

interface UserService {
    public UserDto register(UserDto user);
    public UserDto update(UserDto user);
    public UserDto login(UserDto user)
}

第2步:使UserController将UserService作为依赖项

public class UserController {

    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    public UserDto register(UserDto user) {
       userService.register(user);
    } 

    public UserDto update(UserDto user) {
        userService.update(user);

    }

    public UserDto login(long userId) {
        userService.login(user);
    }

}

步骤3:创建子类以处理将CustomerDto和CustomerBO作为依赖关系的不同类型的用户

class CustomerService implements UserService {
    private CustomerDto userDto;
    private CustomerBO userBO;

    public CustomerService(UserDto userDto,UserBO userBo) {
          this.userDto = (CustomerDto)userDto;
          this.userBO= (CustomerBO)userBo;
    }

    //implement register,login and update methods to operate on userDto and userBo
}

以类似的方式实现DriverService类,分别依赖于DriverBoDriverDto对象。

步骤4:实现一个运行时工厂,决定将哪个服务传递给UserController

public UserControllerFactory {
    public static void createUserController(UserDto user) {
       if(user.getTypeOfUser().equlas(CUSTOMER)) { 
           return new UserController(new CustomerService(user));
       } else if(user.getTypeOfUser().equlas(DRIVER)) {
           return new UserController(new DriverService(user));
       }
    }

}

步骤5致电工厂以创建用户控制器

UserDto userDto = someMethodThatCreatesUserDto(();
UserController controller = UserControllerFactory.createUserController(user);
controller.register();
controller.update();
controller.login();

上述方法的优点是switch / if-else语句可以一直移动到单个类即工厂。

你想要这样的东西:

public abstract class User {
    abstract void register();
    abstract void update();
    abstract void login();

    // maybe some more common non-abstract methods
}

任何类型的User都有一个扩展此抽象类的类,因此必须实现其所有抽象方法,如下所示:

public class Driver extends User {
    public void register() {
        // do whatever a driver does when register...
    }
    public void update() {
        // do whatever a driver does when update...
    }
    public void login() {
        // do whatever a driver does when login...
    }
}

public class Customer extends User {
    public void register() {
        // do whatever a customer does when register...
    }
    public void update() {
        // do whatever a customer does when update...
    }
    public void login() {
        // do whatever a customer does when login...
    }
}

这样,您就可以避免任何开关案例代码。 例如,您可以拥有一个User数组,每个User都将使用new Driver()new Customer()进行实例化。 然后,例如,如果您正在遍历此数组并执行所有Userlogin()方法,则将根据其特定类型调用每个用户的login()==>无需切换案例,无需进行转换!

非常简单的示例(仅适用于DriverDto和CustomerDto的不同登录逻辑) - 我已经从字段typeOfUser辞职(因为在我的解决方案中没有必要) - 我不确定这在您的解决方案中是否可行:

public abstract class UserDto {
    // put some generic data & methods here
}

public class CustomerDto extends UserDto {

    private String customerName;

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
}

public class DriverDto extends UserDto {

    private String driverName;

    public String getDriverName() {
        return driverName;
    }

    public void setDriverName(String driverName) {
        this.driverName = driverName;
    }
}

public class ThisIsServiceOrDelegateToOtherServices {

    public void login(CustomerDto customer) {
        String name = customer.getCustomerName();
        System.out.println(name);
        // work on name here
    }

    public void login(DriverDto customer) {
        String name = customer.getDriverName();
        System.out.println(name);
        // work on name here
    }

}

用法:

public static void main(String... args) {
    //demo data
    CustomerDto customer = new CustomerDto();
    customer.setCustomerName("customerName");
    DriverDto driver = new DriverDto();
    driver.setDriverName("driverName");
    // usage
    ThisIsServiceOrDelegateToOtherServices service = new ThisIsServiceOrDelegateToOtherServices();
    service.login(customer);
    service.login(driver);
}

如果你真的需要在TypeOfUser TypeOfUser -enum,那么你可以用一个服务扩展你的枚举。 因此,您创建一个TypeOfUserService接口。 CustomerSerivce和DriverService将继承该服务:

    public interface TypeOfUserService {
       public void register(UserDTO user);
       // ...
    }

    public class CustomerService implements TypeOfUserService {
       @Override
       public void register(UserDTO user) {
         // ...
       }
    }

    public class DriverService implements TypeOfUserService {
       @Override
       public void register(UserDTO user) {
         // ...
       }
    }

然后在TypeOfUser枚举中创建注册,更新等方法:

public enum TypeOfUser {

  DRIVER(new DriverService()), 
  CUSTOMER(new CustomerService());

  private TypeOfUserService typeOfUserService;

  TypeOfUser(TypeOfUserService typeOfUserService) {
    this.typeOfUserService = typeOfUserService;
  }

  public static void register(String typeOfUser, UserDTO user) {
     TypeOfUser.valueOf(typeOfUser).typeOfUserService.register(user);
  } 
  // ...

 }

然后,您可以通过以下方式调用register方法:

    class UserController() {
      public UserDto register(UserDto user) { 
        TypeOfUser.register(user.getTypeOfUser, user);
      }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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