首先以一个例子引入,传统方法,不使用遵循OCP开闭原则的弊端
代码结构:
public interface UserDaoImpl {
/*返回用户ID类型*/
String getUserType(String userId);
}
public class UserDao implements UserDaoImpl {
@Override
public String getUserType(String userId) {
// 假设这里根据用户 ID 返回用户类型
if ("user1".equals(userId)) {
return "Admin";
} else if ("user2".equals(userId)) {
return "Member";
}
return "Guest";
}
}
public interface UserServiceImpl {
void printUserDetails(String userId);
}
public class UserService implements UserServiceImpl {
private UserDaoImpl userDaoImpl = new UserDao();
@Override
public void printUserDetails(String userId) {
String userType = userDaoImpl.getUserType(userId);
// 根据用户类型打印不同的信息
if ("Admin".equals(userType)) {
System.out.println("Welcome, Admin! You have full access.");
} else if ("Member".equals(userType)) {
System.out.println("Welcome, Member! You have limited access.");
} else {
System.out.println("Welcome, Guest! Please register to access more features.");
}
}
}
public class UserDaoController {
private UserServiceImpl userServiceImpl = new UserService();
public void handleRequest(String userId) {
userServiceImpl.printUserDetails(userId);
}
}
public class Main {
public static void main(String[] args) {
UserDaoController controller = new UserDaoController();
controller.handleRequest("user1"); // 输出: Welcome, Admin! You have full access.
controller.handleRequest("user2"); // 输出: Welcome, Member! You have limited access.
controller.handleRequest("user3"); // 输出: Welcome, Guest! Please register to access more features.
}
}
问题:
"VIP"
用户),必须修改 UserService
中的 printUserDetails
方法,添加新的 if-else
分支。if ("VIP".equals(userType)) {
System.out.println("Welcome, VIP! Enjoy exclusive benefits.");
}
UserService
直接依赖于具体的用户类型逻辑(如 "Admin"
、"Member"
),导致代码难以扩展和维护。那么如何去解决这个问题呢。
我们可以通过引入 策略模式 和 抽象接口 来改进代码,使其符合 OCP。以下是改进后的代码:
// 定义用户行为接口
public interface UserBehavior {
void printMessage();
}
// 不同用户类型的实现
public class AdminBehavior implements UserBehavior {
@Override
public void printMessage() {
System.out.println("Welcome, Admin! You have full access.");
}
}
public class MemberBehavior implements UserBehavior {
@Override
public void printMessage() {
System.out.println("Welcome, Member! You have limited access.");
}
}
public class GuestBehavior implements UserBehavior {
@Override
public void printMessage() {
System.out.println("Welcome, Guest! Please register to access more features.");
}
}
// 工厂类:根据用户类型返回对应的实现
public class UserBehaviorFactory {
public static UserBehavior getBehavior(String userType) {
switch (userType) {
case "Admin":
return new AdminBehavior();
case "Member":
return new MemberBehavior();
case "Guest":
return new GuestBehavior();
default:
throw new IllegalArgumentException("Unknown user type: " + userType);
}
}
}
// 修改后的 Service 层
public class UserService {
private UserDao userDao = new UserDao();
public void printUserDetails(String userId) {
String userType = userDao.getUserType(userId);
// 使用工厂类获取对应的行为实现
UserBehavior behavior = UserBehaviorFactory.getBehavior(userType);
behavior.printMessage();
}
}
// 其他层保持不变
public class UserController {
private UserService userService = new UserService();
public void handleRequest(String userId) {
userService.printUserDetails(userId);
}
}
// 测试类
public class Main {
public static void main(String[] args) {
UserController controller = new UserController();
controller.handleRequest("user1"); // 输出: Welcome, Admin! You have full access.
controller.handleRequest("user2"); // 输出: Welcome, Member! You have limited access.
controller.handleRequest("user3"); // 输出: Welcome, Guest! Please register to access more features.
}
}
但上面代码还不是很成功,当用户类型增加,那么工厂类是不是又要继续去switch...case了呢,此时我们只是提出传统写法是违反OCP开闭原则的
public class MySQLDatabase {
public void save(String data) {
System.out.println("Saving data to MySQL: " + data);
}
}
public class UserService {
private MySQLDatabase database;
public UserService() {
this.database = new MySQLDatabase();
}
public void saveUser(String user) {
database.save(user);
}
}
问题此时就会出现
UserService
直接依赖于 MySQLDatabase
,如果未来需要切换到其他数据库(如 MongoDB),就需要修改 UserService
的代码。UserService
)依赖于低层模块(MySQLDatabase
)的具体实现。通过引入一个抽象接口 Database
,使 UserService
和 MySQLDatabase
都依赖于这个接口:
// 抽象接口
public interface Database {
void save(String data);
}
// 具体实现
public class MySQLDatabase implements Database {
@Override
public void save(String data) {
System.out.println("Saving data to MySQL: " + data);
}
}
public class MongoDBDatabase implements Database {
@Override
public void save(String data) {
System.out.println("Saving data to MongoDB: " + data);
}
}
// 高层模块
public class UserService {
private Database database;
public UserService(Database database) {
this.database = database;
}
public void saveUser(String user) {
database.save(user);
}
}
这样子就可以实现,当我去在调用时,总结使用多态传递相关的子类引用,那么就可以达到后期增加业务时,加代码,总结创建类,实现接口即可,不会去修改原有代码。