我知道已经有类似的问题,但看着它们我仍然对如何设计我的代码有一些疑问。我有一项服务允许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
本身添加 registration / login / update / delete 的方法吗? ?我对如何做到这一点并不清楚,任何帮助都表示赞赏。
答案 0 :(得分:2)
我想用更好的设计取而代之。
替换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
类,分别依赖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 userDto = someMethodThatCreatesUserDto(();
UserController controller = UserControllerFactory.createUserController(user);
controller.register();
controller.update();
controller.login();
上述方法的优点是switch / if-else语句会一直移动到单个类,即工厂。
答案 1 :(得分:1)
你想要这样的东西:
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
个数组,每个数组都将使用new Driver()
或new Customer()
进行实例化。然后,例如,如果您正在迭代此数组并执行所有User
s login()
方法,则将根据其特定类型调用每个用户的login()==>无需开关箱,无需铸造!
答案 2 :(得分:0)
非常简单的示例(仅适用于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);
}
答案 3 :(得分:0)
如果你真的需要在你的UserDTO中使用TypeOfUser
- 枚举,那么你可以用一个服务扩展你的枚举。因此,您创建一个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);
}
// ...
}
然后您可以通过以下方式调用注册方法:
class UserController() {
public UserDto register(UserDto user) {
TypeOfUser.register(user.getTypeOfUser, user);
}
}