Spring之控制反转概念梳理(二)

Spring到底是什么,包括哪些内容(二)

先回答上一篇博文中的主要问题:为什么Spring的控制反转非常受欢迎并且广泛被使用。
先从一个需求开始:
一家公司最初使用百度云服务,后来更换为阿里云服务,再后来更换为其它公司的云服务…
⒈、正常的Java代码执行模式:
⑴、公司:

 public class Company {
	...
	//使用百度云服务,持有它的引用
    private BaiduServerService 	Service;
    //构造方法
    public Company(BaiduServerService Service){
       //初始化云服务
       this.Service = Service;
    }
    //使用云服务
	public void Service() {
		Service.Service();
	}
	...
 }

⑵、创建百度云服务:

 public class BaiduServerService {
    //百度云提供服务
	public void Service() {
		System.out.print("百度云服务");
	}
	...
 }

⑶、测试:

 import com.Company.www.Company;
 import com.ServerService.www.BaiduServerService;

 public class Test {
	public static void main(String[] args) {
	   //创建百度云服务对象
	   BaiduServerService service = new BaiduServerService();
	   //创建公司对象,传入百度云服务对象
	   Company company = new Company(service);
	   //使用百度云服务
	   company.Service();
	}
 }

结果示例:
结果示例
⑷、更换为阿里云服务:
①、首先将公司持有的云服务引用由百度云更换为阿里云:

 public class Company {
	...
	//公司持有的云服务引用类型由BaiduServerService
	//(百度云服务)更换为AliBabaServerService
	//(阿里云服务)
    private AliBabaServerService Service;
    //构造方法
    public Company(AliBabaServerService Service){
       //初始化云服务
       this.Service = Service;
    }
    //使用云服务
	public void Service() {
		Service.Service();
	}
	...
  }

②、创建阿里云服务:

public class AliBabaServerService {
    //阿里云提供服务
	public void Service() {
		System.out.print("阿里云服务");
	}
	...
 }

③、重新测试:

 import com.Company.www.Company;
 import com.ServerService.www.AliBabaServerService;

 public class Test {
	public static void main(String[] args) {
	   //创建阿里云服务对象
	   AliBabaServerService service = new AliBabaServerService();
	   //创建公司对象,传入阿里云服务对象
	   Company company = new Company(service);
	   //使用阿里云服务
	   company.Service();
	}
 }

结果示例:
结果示例:
⑸、更换为华为云服务:

⑹、换回百度云服务:

如果有兴趣,可以自行尝试实现后面更换云服务的代码,在这里就不一一列出了。
总结一下上面代码模式存在的问题:
①、代码维护(更换云服务)非常繁琐,更何况这里只是简单的Java示例类,实际的应用类代码维护可想而知。
②、重复性代码比重过大(对比百度云服务和阿里云服务的代码,重复性比例至少百分之八十)。
③、无法测试(一种云服务类型就需要匹配一个测试类)。
代码组织架构截图:
代码的组织架构
上面的代码能不能通过某种方式改进,降低维护的成本?
有,通过接口降低类之间的耦合度。
⑴、新增云服务接口:

 interface ServerService{
    public void Service();
 }

⑵、公司与云服务接口耦合,不再与具体的云服务耦合:

 import com.ServerService.www.ServerService;

 public class Company {
    //持有云服务接口引用
    private ServerService Service;
    //构造方法
    public Company(ServerService Service){
       //初始化云服务
       this.Service = Service;
    }
    //使用云服务
	public void Service() {
		Service.Service();
	}
 }

⑶、创建百度云服务:

//implements云服务接口ServerService
public class BaiduServerService implements ServerService{
	public void Service() {
		System.out.print("百度云服务");
	}
}

⑷、测试:

 import com.Company.www.Company;
 import com.ServerService.www.BaiduServerService;
 import com.ServerService.www.ServerService;

 public class Test {
	public static void main(String[] args) {
	   //接口引用持有子类对象(多态)
	   ServerService service = new BaiduServerService();
	   //创建公司对象,传入云服务对象(实际是百度云对象)
	   Company company = new Company(service);
	   //使用云服务(实际是百度云服务)
	   company.Service();
	}
 }

⑸、更换为阿里云服务:
①、创建阿里云服务(需要implements云服务接口ServerService):

//implements云服务接口ServerService
public class AliBabaServerService implements ServerService{
    //阿里云提供服务
	public void Service() {
		System.out.print("阿里云服务");
	}
	...
 }

②、重新测试:

```javascript
 import com.Company.www.Company;
 import com.ServerService.www.AliBabaServerService;

 public class Test {
	public static void main(String[] args) {
	   //由BaiduServerService(百度云服务)更换为
	   //AliBabaServerService(阿里云服务)
	   ServerService service = new AliBabaServerService();
	   //创建公司对象,传入云服务对象(实际是百度云对象)
	   Company company = new Company(service);
	   //使用阿里云服务
	   company.Service();
	}
 }

总结一下上面代码模式存在的问题:
①、代码维护(更换云服务)繁琐程度稍有降低,至少在更换云服务的过程中不再需要维护公司类。
②、重复性代码比重稍有降低。
③、无法测试的状况仍然没有改变(如图)。
因为更换云服务始终需要修改测试类的内容才能测试。
无法测试的状况仍然没有改变
还有没有什么方式能进一步降低维护的成本?
有,通过Spring的控制反转。
⑴、云服务接口:

 interface ServerService{
    public void Service();
 }

⑵、公司(与云服务接口耦合,不再与具体的云服务类耦合):

 import com.ServerService.www.ServerService;

 public class Company {
    //持有云服务接口引用
    private ServerService Service;
    //构造方法
    public Company(ServerService Service){
       //初始化云服务
       this.Service = Service;
    }
    //使用云服务
	public void Service() {
		Service.Service();
	}
 }

⑶、创建百度云服务:

//implements云服务接口ServerService
public class BaiduServerService implements ServerService{
	public void Service() {
		System.out.print("百度云服务");
	}
}

⑷、将所有的类都配置到Spring的配置文件中:

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    //通过Spring配置文件的<Bean>标签配置类Company
    <bean id="company" class="com.Company.www.Company">
       //具体的标签意义后续的博文会详细描述,这里简单说明
       //这个标签的存在意义是说明类Company与类BaiduServerService
       //的关系
       <constructor-arg ref="Baidu" />
    </bean>
    //通过Spring配置文件的<Bean>标签配置类BaiduServerService
    <bean id="Baidu" class="com.ServerService.www.BaiduServerService">
    </bean>
 </beans>

⑸、测试:

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import com.Company.www.Company;

@SuppressWarnings("deprecation")
public class Test {
	public static void main(String[] args) {
		//注解,表示已经废弃,不再使用
    	@SuppressWarnings("deprecation")
    	//创建一个容器对象(容器的来源是XML文件"Bean.xml")
		XmlBeanFactory factory = new XmlBeanFactory
                 (new ClassPathResource("Bean.xml"));
        //从容器中获取一个名为"company"的对象
    	Company company = (Company) factory.getBean("company");
    	//使用云服务
		company.Service();
	}
}

结果示例:
结果示例
⑹、更换为阿里云服务:
①、创建阿里云服务(需要implements云服务接口ServerService):

```javascript
public class AliBabaServerService {
    //阿里云提供服务
	public void Service() {
		System.out.print("阿里云服务");
	}
	...
 }

②、将阿里云服务类配置到Spring的配置文件中:

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    //通过Spring配置文件的<Bean>标签配置类Company
    <bean id="company" class="com.Company.www.Company">
       //更换云服务的重点在这里:只需要更换
       //Company与具体云服务类的关系
       <constructor-arg ref="AliBaba" />
    </bean>
    //可以将百度云服务类保留或者注释,不建议删除
    <!--<bean id="Baidu" class="com.ServerService.www.BaiduServerService">
    </bean>  -->
    //通过Spring配置文件的<Bean>标签配置类AliBabaServerService
    <bean id="AliBaba" class="com.ServerService.www.AliBabaServerService">
    </bean>
 </beans>

③、测试:
同上,因为测试类不需要作任何修改。
结果示例:
结果示例
总结一下上面代码模式存在的问题:
①、代码维护(更换云服务)繁琐程度大大降低。
②、重复性代码比重大大降低。
③、测试非常方便。
目前的编程环境都提倡低侵入式,就拿更换云服务的例子来说,你只能关注业务本身,也就是提供新的云服务类型以及实现,其它内容(比如测试代码)根本无法修改。
Spring的控制反转非常适合目前的编程环境,如果不满意当前的实现,那么就提供新的实现,再将新的实现丢进Spring的容器中,剩下的都交给容器(相对而言,Spring配置文件替换维护部分可以忽略不计)。
Spring的控制反转提供的另一个附加好处是:所有的维护都集中在一个文件中,非常方便。
PS:时间有限,有关Spring的内容会持续更新!今天就先写这么多,如果有疑问或者有兴趣,可以加QQ:2649160693,并注明CSDN,我会就博文中有疑义的问题做出解答。同时希望博文中不正确的地方各位加以指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值