记录对设计模式学习的过程
定义:高层模块不应以依赖低层模块,二者都应依赖其抽象
抽象不应该依赖细节;细节应该依赖抽象
针对接口编程,不要针对实现编程
优点:低耦合 、、、、等等
详细概念可以网上查询
有一个查询数据的类SearchDao.java
package com.dsdj.design.principle.dependenceinversion; /** * @ClassName SearchDao * @Description TODO * @Author dsdj * @Date 2018/10/9 下午7:46 * @Version 1.0 **/ public class SearchDao { public void getUsers(){ System.out.println("查询人员的功能"); } public void getBooks(){ System.out.println("查询图书的功能"); } }
package com.dsdj.design.principle.dependenceinversion; /** * @ClassName SearchDao * @Description TODO * @Author dsdj * @Date 2018/10/9 下午7:46 * @Version 1.0 **/ public class SearchDao { public void getUsers(){ System.out.println("查询人员的功能"); } public void getBooks(){ System.out.println("查询图书的功能"); } }
测试类
package com.dsdj.design.principle.dependenceinversion; /** * @ClassName Test * @Description TODO * @Author dsdj * @Date 2018/10/9 下午7:50 * @Version 1.0 **/ public class Test { public static void main(String[] args) { SearchDao searchDao = new SearchDao(); searchDao.getBooks(); searchDao.getUsers(); } }
package com.dsdj.design.principle.dependenceinversion; /** * @ClassName Test * @Description TODO * @Author dsdj * @Date 2018/10/9 下午7:50 * @Version 1.0 **/ public class Test { public static void main(String[] args) { SearchDao searchDao = new SearchDao(); searchDao.getBooks(); searchDao.getUsers(); } }
如果我们需要新增一个查询课程的类,只要再添加一个方法就好了,这个是典型的面向实现的编程。
新增需求,我们需要查找课程的集合,该怎么写呢?
需要在SearchDao中添加getCourse()的方法,然后在Test中重新调用getCourse()方法
是不是觉得这样做很麻烦?
这个类需要经常修改,导致扩展性比较差
上面的例子,Test.java是高层次的类,SearchDao.java是低层次的类。根据依赖导致的原则,高层次的类是不依赖低层次的模块的。Test依赖SearchDao的具体实现。导致没增加一个功能,只能去底层模块添加修改,高层模块才能使用。
1.进行抽象,提取公共方法getList();
/** * @ClassName GetListDao * @Description TODO * @Author dsdj * @Date 2018/10/9 下午8:14 * @Version 1.0 **/ public interface GetListDao { void getList(); }
/** * @ClassName GetListDao * @Description TODO * @Author dsdj * @Date 2018/10/9 下午8:14 * @Version 1.0 **/ public interface GetListDao { void getList(); }
2.对每个实现,写一个实现类
实现获取用户的类
public class UserDao implements GetListDao { public void getList() { System.out.println("获取User的集合"); } }
public class UserDao implements GetListDao { public void getList() { System.out.println("获取User的集合"); } }
实现获取图书的类
public class BookDao implements GetListDao { public void getList() { System.out.println("获取book的集合"); } }
public class BookDao implements GetListDao { public void getList() { System.out.println("获取book的集合"); } }
3.重写SearchDao
package com.dsdj.design.principle.dependenceinversion; /** * @ClassName SearchDao * @Description TODO * @Author dsdj * @Date 2018/10/9 下午7:46 * @Version 1.0 **/ public class SearchDao { private GetListDao getListDao; public SearchDao(GetListDao getListDao){ this.getListDao=getListDao; } public void setGetListDao(GetListDao getListDao) { this.getListDao = getListDao; } public void searchlist(){ getListDao.getList(); } }
package com.dsdj.design.principle.dependenceinversion; /** * @ClassName SearchDao * @Description TODO * @Author dsdj * @Date 2018/10/9 下午7:46 * @Version 1.0 **/ public class SearchDao { private GetListDao getListDao; public SearchDao(GetListDao getListDao){ this.getListDao=getListDao; } public void setGetListDao(GetListDao getListDao) { this.getListDao = getListDao; } public void searchlist(){ getListDao.getList(); } }
Test
public class Test { public static void main(String[] args) { // SearchDao searchDao = new SearchDao(); // searchDao.getBooks(); // searchDao.getUsers(); // 重构之后的写法 SearchDao searchDao = new SearchDao(new BookDao()); // 获取图书 searchDao.searchlist(); // 获取用户 searchDao.setGetListDao(new UserDao()); searchDao.searchlist(); } }
public class Test { public static void main(String[] args) { // SearchDao searchDao = new SearchDao(); // searchDao.getBooks(); // searchDao.getUsers(); // 重构之后的写法 SearchDao searchDao = new SearchDao(new BookDao()); // 获取图书 searchDao.searchlist(); // 获取用户 searchDao.setGetListDao(new UserDao()); searchDao.searchlist(); } }
这样是不是就很有层次感了,
根据依赖倒置的原则:高层没有依赖底层的模块。例如SearchDao是高层模块,并没有依赖底层的UserDao、BookDao模块。有新需求的时候,只要再底层模块进行扩展。获取其他数据不会影响已经写好的模块。
相对于细节的多样性,抽象就稳定多了,故以抽象为基础搭建起来的架构就稳定多了。
现在我们再回头看看spring的依赖注入、控制反转,是不是有了新的理解了。代码不需要费心具体的实现类,把具体的实现类的权利交给容器负责就好了。
我们回来再看之前的需求:新增一个获取课程的需求
我们可以怎么写呢?
写一个实现类CourseDao
public class CourseDao implements GetListDao { public void getList() { System.out.println("获取course集合"); } }
public class CourseDao implements GetListDao { public void getList() { System.out.println("获取course集合"); } }
Test调用
public class Test { public static void main(String[] args) { // SearchDao searchDao = new SearchDao(); // searchDao.getBooks(); // searchDao.getUsers(); // 重构之后的写法 SearchDao searchDao = new SearchDao(new BookDao()); // 获取图书 searchDao.searchlist(); // 获取用户 searchDao.setGetListDao(new UserDao()); searchDao.searchlist(); // 新增需求:获取课程 searchDao.setGetListDao(new CourseDao()); searchDao.searchlist(); } }
public class Test { public static void main(String[] args) { // SearchDao searchDao = new SearchDao(); // searchDao.getBooks(); // searchDao.getUsers(); // 重构之后的写法 SearchDao searchDao = new SearchDao(new BookDao()); // 获取图书 searchDao.searchlist(); // 获取用户 searchDao.setGetListDao(new UserDao()); searchDao.searchlist(); // 新增需求:获取课程 searchDao.setGetListDao(new CourseDao()); searchDao.searchlist(); } }
运行结果
这样就可以不破坏原来的代码而实现新的功能了。