Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.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_Polymorphism_Visitor - Fatal编程技术网

Java 将开关盒更换为新的

Java 将开关盒更换为新的,java,design-patterns,polymorphism,visitor,Java,Design Patterns,Polymorphism,Visitor,我知道已经有类似的问题了,但是看着它们,我仍然对我应该如何设计我的代码有一些疑问。我有一个允许用户注册/登录/更新/删除的服务。问题是,User是一个抽象类型,它包含数据typeOfUser,实际的注册/更新/删除方法应该基于该数据调用,现在我在一个开关案例块中这样做。我想换个更好的设计 UserController.java public class UserController { public UserDto register(UserDto user) { sw

我知道已经有类似的问题了,但是看着它们,我仍然对我应该如何设计我的代码有一些疑问。我有一个允许用户注册/登录/更新/删除的服务。问题是,
User
是一个抽象类型,它包含数据
typeOfUser
,实际的注册/更新/删除方法应该基于该数据调用,现在我在一个
开关案例
块中这样做。我想换个更好的设计

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
本身中添加注册/登录/更新/删除方法吗?我真的不知道该怎么做,非常感谢您的帮助。

您可能需要这样的帮助:

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

    // maybe some more common non-abstract methods
}
任何类型的用户都将拥有一个扩展此抽象类的类,因此必须实现其所有抽象方法,如下所示:

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
s数组,每个数组都将使用
newdriver()
newcustomer()
进行实例化。然后,例如,如果您在该数组上迭代并执行所有的
User
s
login()
方法,则每个用户的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);
}

如果您确实需要UserDTO中的
TypeOfUser
-enum,那么您可以使用一个服务扩展您的enum。所以您创建了一个TypeOfUserService接口。CustomerSerivce和DriversService将从该服务继承:

    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枚举中创建register、update等方法:

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);
      }
    }
我想换个更好的设计

替换
switch
语句并利用多态性的第一步是确保每个操作都有一个契约(读取方法签名),而不管用户类型如何。以下步骤将解释如何实现这一点:

步骤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);
    }

}
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
}
步骤3:创建子类以处理将CustomerTo和CustomerBO作为依赖项的不同类型的用户

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

}
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
类,分别依赖于
DriverBo
DriverDto
对象

步骤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 user = someMethodThatCreatesUserDto(();
UserController controller = UserControllerFactory.createUserController(user);
controller.register();
controller.update();
controller.login();

上述方法的优点是switch/if-else语句被移动回一个类,即factory。

诀窍是使用一个通用服务,然后用一个用户作为输入调用它一次,即调用
service.register(user)
一次,而不是使用
开关
语句。@TimBiegeleisen是的,但是如何实现“更新(用户)”呢?因为更新与客户端或驱动程序特定的字段一起工作。所以它不能真正使用一般服务,它必须使用特定的。我指出多态性可以帮助你的一种方法。您可能需要这样一个switch语句,尽管它不一定在这里。@wesleyy的
Visitor
模式解决了一个非常特殊的问题,并且在大多数情况下(如果不是全部的话)几乎都是一个过火的问题。请参阅我的答案,了解如何用简单的多模态来解决这个问题。有用的上下文:问题是“register(UserDto user)”方法只能根据“typeOfUser”字段决定注册的用户类型。我认为为每种用户创建一个单独的注册端点是不可伸缩的,你认为我错了吗?@wesleyy在我的实现中,你根本不需要
UserDto-user
参数,这正是它的优点,也是多态性的优点。该实现是特定于类型的,因此类
驱动程序
将有自己的注册、更新和登录方式,客户也是如此。这正是它的可扩展性所在,一旦你有了一个新类型的
用户
,你创建了一个扩展
用户
的新类,实现了抽象方法,你就可以开始了,你不必接触任何其他现有类。好吧,但是当我通过网络向你发送一个用户对象json时,如何确定要调用谁的.register)方法?您必须调用具体类型的方法,并且类型信息仅存储在json@wesleyyJSON是另一回事,它与业务逻辑层无关。但是如果我理解正确,根据JSON中的typeOfUser字段,您将实例化正确的用户。因此,如果它是
typeOfUser:'driver'
您将转到
User u1=newdriver()
。然后,当您调用
u1.register()
时,将根据u1的运行时类型调用右侧的
register()
,在这种情况下,它是
Driver
。@wesleyy当您解组JSON时,您必须处理使对象成为正确类型的问题。如果您使用的是JAXB,这可能会很有用。可能是我在互联网上看到的多态性的最好解释。@Liga谢谢!!这是我多年来对StackOverflow的贡献中得到的最好的赞扬;)关于这个话题,我有更多的答案1)2)3)只是一个简短的说明,你认为呢