Spring学习目录
启示代码
一个简单的业务需求:使用Mysql和MVC三层架构根据id删除用户
dao层(持久层):
创建接口:
/**
* 专门负责用户增删改查
*/
public interface UserDao {
/**
* 根据id删除用户信息
*/
void deleteById();
}
创建接口的实现类:
public class UserDaoImplMysql implements UserDao {
@Override
public void deleteById() {
System.out.println("Mysql删除用户信息");
}
}
Service层(业务层):
业务接口:
/**
* 业务层,处理业务逻辑
*/
public interface UserService {
/**
* 删除用户信息
*/
void deteleUser();
}
业务层实现类:
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImplMysql();
@Override
public void deteleUser() {
userDao.deleteById();
}
}
web层:
public class UserAction {
UserService userService = new UserServiceImpl();
public void deleteRequest(){
userService.deteleUser();
}
}
测试程序:
public class Test {
public static void main(String[] args) {
UserAction userAction = new UserAction();
userAction.deleteRequest();
}
}
代码存在的问题
如果用了一段时间后,客户改需求,想要用Oracle数据库,那么程序需要改动的地方
- 1.dao层,提供一个Oracle实现类
public class UserDaoImplOracle implements UserDao {
@Override
public void deleteById() {
System.out.println("Oracle删除用户信息");
}
}
- 2.service层,UserDao对象需要从new Mysql实现类改为new Oracle实现类
private UserDao userDao = new UserDaoImplOracle();
- 3.需要对之前的所有的程序进行测试
违反OCP原则,DIP原则
-
OCP:开闭原则,对修改关闭(使用方),对扩展开放(提供方)。最重要、最核心、最基础的原则。
软件需要变化时,尽量通过扩展软件实体行为来实现变化,而不是通过修改已有的代码来实现变化。
当进行系统功能扩展的时候,如果修改了之前稳定的程序,那么之前所有的程序都要进行重新测试,这是非常麻烦的。 -
DIP:依赖倒转(倒置)原则,核心是面向接口编程
- 1.高层模块不应该依赖底层模块,二者应该依赖其抽象。
- 2.抽象不应该依赖–细节(指具体实现类),细节应该依赖–抽象(指接口和抽象类)。
例如当前程序,从高层到低层 UserAction - UserServiceImpl - UserDaoImplMysql
表示层UserAction 依赖了 业务层具体的的UserServiceImpl
业务层的UserServiceImpl 又依赖了 持久层具体的的UserDaoImplMysql
只要底层模块改变,高层必然受到牵连,所以违反了DIP原则,怎么遵守DIP,要面向接口编程,面向抽象编程,不要面向具体。
引出IoC(控制反转)
当前程序怎么让其遵守OCP和DIP原则,采用”控制反转“这种编程思想。
控制反转:Ioc(Inversion of Control),是一种新型的设计模式,由于比较新,没有被纳入到GoF23种设计模式之中。
控制反转的核心:
- 其一:不采用硬编码方式new对象。
- 其二:不采用硬编码的方式来维护对象的关系。
控制反转的实现方式有多种,比较重要的是:依赖注入(Dependency Injection 简称DI)。
- 依赖:A对象和B对象的关系。
- 注入:通过手段让A与B产生关系(依赖)。
DI有包括两种常见的方式:
- 1.set注入(执行set方法给属性赋值)
- 2.构造方法注入(执行构造方法给属性赋值)
引出Spring框架
首先,对当前程序进行改造
1.service,UserDao不 new 具体的实现类了。
2.UserAction也不new具体的service实现类。
3.使用set注入或者构造方法注入
service:
public class UserServiceImpl implements UserService {
//private UserDao userDao = new UserDaoImplMysql();
//private UserDao userDao = new UserDaoImplOracle();
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void deteleUser() {
userDao.deleteById();
}
}
web:
public class UserAction {
//UserService userService = new UserServiceImpl();
UserService userService;
public UserAction(UserService userService) {
this.userService = userService;
}
public void deleteRequest(){
userService.deteleUser();
}
}
测试程序:
public class Test {
public static void main(String[] args) {
//UserAction userAction = new UserAction();
UserAction userAction = new UserAction(new UserServiceImpl(new UserDaoImplOracle()));
userAction.deleteRequest();
}
}
如果把这个Test看成一个Servlet,显然,具体需要用哪一个实现类,还是需要开发人员自己去new,如果这些实现类相当多,那么new的这个操作会相当复杂,可读性就会变差。
我们可以使用Spring框架,让框架帮我们管理这些对象。
Spring框架:Spring框架实现了控制反转Ioc这种思想的容器
-
1.可以帮你new对象
-
2.可以帮你维护对象之间的关系