web分层解耦与三层架构
分层解耦是软件开发中一种设计思想,通过将系统划分为多个层次,每层专注于特定职责,降低模块间的直接依赖。三层架构是分层解耦的经典实践,包括:
- 表现层(Controller):处理用户请求和响应。
- 业务逻辑层(Service):处理核心业务逻辑。
- 数据访问层(DAO):负责数据持久化操作。
三层架构的代码实现
数据访问层(DAO)
// 定义数据访问接口(面向接口编程,解耦具体实现)
public interface UserDao<T> {
// 泛型T表示操作的实体类型(如User)
T findById(int id);
void save(T entity);
}
// 实现类(多态:接口的多种实现方式)
public class UserDaoImpl implements UserDao<User> {
@Override
public User findById(int id) {
// 模拟数据库查询
return new User(id, "张三");
}
@Override
public void save(User user) {
System.out.println("保存用户: " + user.getName());
}
}
业务逻辑层(Service)
// 业务接口(定义服务契约)
public interface UserService {
String getUserName(int id);
}
// 实现类(依赖DAO层)
public class UserServiceImpl implements UserService {
// 接口注入(多态:实际运行时传入的是UserDaoImpl)
private UserDao<User> userDao;
public UserServiceImpl(UserDao<User> userDao) {
this.userDao = userDao;
}
@Override
public String getUserName(int id) {
// 调用DAO层获取数据
User user = userDao.findById(id);
// 业务逻辑处理
return user != null ? user.getName() : "用户不存在";
}
}
表现层(Controller)
// 控制器(处理HTTP请求)
public class UserController {
// 依赖Service层(面向接口)
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public String getUser(int id) {
// 调用Service层处理业务
return userService.getUserName(id);
}
}
调用关系与解耦逻辑
-
Controller调用Service
- 原因:Controller负责协调请求,但不处理具体业务。通过调用Service,确保业务逻辑可复用(如多个Controller共用同一Service)。
- 解耦:Controller仅依赖Service接口,不关心具体实现(如
UserServiceImpl
或MockUserService
)。
-
Service调用DAO
- 原因:Service负责业务规则,但数据存取细节应由DAO处理。例如,添加缓存时只需修改DAO,不影响Service。
- 解耦:Service通过DAO接口操作数据,数据库类型(MySQL/MongoDB)或ORM框架(Hibernate/MyBatis)的变化不影响业务层。
生活中的类比:餐厅分工
-
Controller → 服务员
接收顾客点单(请求),但不负责烹饪,将订单传递给后厨(Service)。 -
Service → 厨师
根据订单制作菜品(业务逻辑),但不需要知道食材如何采购(DAO)。 -
DAO → 采购员
负责从市场获取食材(数据库操作),不关心菜品如何烹饪。
关键概念解释
-
泛型(Generics)
- 示例:
UserDao<T>
中的T
表示通用数据实体,编译时指定具体类型(如User
),提高代码复用性和类型安全。
- 示例:
-
多态(Polymorphism)
- 示例:
UserDao userDao = new UserDaoImpl()
,运行时实际调用的是UserDaoImpl
的方法,便于替换实现(如切换为JdbcUserDaoImpl
)。
- 示例:
-
接口与实现类
- 接口定义契约(
UserDao
),实现类提供具体行为(UserDaoImpl
)。调用方依赖接口而非具体类,降低耦合。
- 接口定义契约(
完整调用示例
public class Main {
public static void main(String[] args) {
// 依赖注入(实际项目可用Spring等框架)
UserDao<User> dao = new UserDaoImpl();
UserService service = new UserServiceImpl(dao);
UserController controller = new UserController(service);
// 模拟HTTP请求
String userName = controller.getUser(1);
System.out.println("用户名: " + userName); // 输出: 用户名: 张三
}
}