我们将根据一个例子来逐步了解 例子的详细内容:例子
例子的功能:
实现一:以面向对象的方式实现Demo
html报表
public class HtmlReportGenerator {
public void generate(){
System.out.println("生成Html格式的报表!");
}
}
pdf报表
public class PdfReportGenerator {
public void generate(){
System.out.println("生成Pdf格式的报表!");
}
}
报表服务类
public class ReportService {
PdfReportGenerator pdfGenerator=new PdfReportGenerator();
// HtmlReportGenerator htmlGenerator = new HtmlReportGenerator();
public void generateReport(){
System.out.println("收集、汇总数据!");
System.out.println("生成柱状图等图标!");
pdfGenerator.generate();
// htmlGenerator.generate();
}
}
在报表服务类中我们需要哪一种报表就实例化哪种报表
实现二:分离接口和实现
- 优化目标:消除ReportService到ReportGenerator实现类之间的依赖关系
实现一个报表接口类ReportGenerator
public interface ReportGenerator {
public void generate();
}
其他的报表类需要实现ReportGenerator接口并实现generate方法,这里省略其他
public class PdfReportGenerator implements ReportGenerator {
@Override
public void generate() {
// TODO Auto-generated method stub
System.out.println("生成Pdf格式的报表!");
}
}
报表服务类
public class ReportService {
ReportGenerator generator;
public void setGenerator(ReportGenerator generator) {
this.generator = generator;
}
public void generateReport(){
System.out.println("收集、汇总数据!");
System.out.println("生成柱状图等图标!");
generator.generate();
}
public static void main(String[] args) {
PdfReportGenerator pdf = new PdfReportGenerator();
HtmlReportGenerator html = new HtmlReportGenerator();
ReportService service = new ReportService();
service.setGenerator(html);
service.generateReport();
}
}
由于抽象了一个报表接口,需要哪种报表,在报表服务端指定报表接口
实现三:采用容器
- 增加容器类:Container类
- 所有组件由Container类管理
容器类
public class Container {
private static Container instance;
private Map<String, Object> components;
private Container() {
components = new HashMap<String, Object>();
instance = this;
ReportGenerator reportGenerator = new PdfReportGenerator();
components.put("reportGenerator", reportGenerator);
ReportService reportService = new ReportService();
components.put("reportService", reportService);
}
public static Container getInstance(){
if(instance == null)
instance = new Container();
return instance;
}
public Object getComponent(String key) {
return components.get(key);
}
}
测试类
public class Run {
public static void main(String[] args) {
ReportService reportService = (ReportService) Container.getInstance().getComponent("reportService");
reportService.generateReport();
}
}
容器来帮我们new报表类
我们只需要传入所需要的报表类型,容器返回我们那个报表对象
分析:
- ReportService与ReportGenerator的具体实现解耦了
- 选择不同的Generator不需要修改Service
- 缺点
- Container对所管理的所有组件产生了依赖
- ReportService对Container依赖,因为其封装有查找逻辑,所以在重用之前还要修改
- 目标
- 去掉ReportService对Container依赖
实现四:使用服务定位器
-
服务定位器:ServiceLocator类
- 封装查找逻辑
- 对外公开查找组件(Generator)的方法、
服务定位器,将查找报表的那个方法分离出来
public class ServiceLocator {
private static Container container = Container.getInstance();
public static ReportGenerator getReportGenerator(){
return (ReportGenerator) container.getComponent("reportGenerator");
}
}
- 优点:
- 应用服务定位器将查找逻辑从组件里分离出来
- 降低组件在查找方面的复杂性
- 增加组件的重用性
- 这是用于查找资源的通用设计模式,并不局限于查找组件
- JavaEE中的应用,如:JNDI(Java命名和目录接口)
- 局限
- 组件需要知道如何查找资源
概念
- Ioc(Inversion of Control,控制反转):
- 设计原则,解耦组件之间的依赖关系
- DI(DI(Dependency Injection ,依赖注入):
- 具体的设计模式,体现了IoC的设计原则
- 因为DI是IoC最典型的实现,所以术语IoC与DI经常被混用
实现五
- 不需要服务定位器
- 组件(ReportService)增加接受资源的方法(setter)
- 由容器将组件(ReportGenerator)注入到另一个组件(ReportService)
- 优点
-完全面向接口
不同类型的依赖注入
- 主要有三种类型的DI
- 接口注入
- setter注入
- 构造器注入