• 第二十三部分_Spring入门之简单工厂模式


    意图:

    简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。通常它根据自变量的不同返回不同的类的实例。

    适用性:

    简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建出哪一个产品类的实例。

    简单工厂模式的构成:

    • 工厂类(Creator)角色:担任这个角色的是简单工厂模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体类实现。
    • 抽象产品(Product)角色:担任这个角色的类是简单工厂模式所创建的对象的父类,或它们共同拥有的接口。抽象产品角色可以用一个接口或者抽象类实现。
    • 具体产品角色(Concrete Product):简单工厂模式所创建的任何对象都是这个角色的实例,具体产品角色由一个具体类实现。

    下面建立一个Java Project来实现简单工厂模式:

    新建simplefactory项目,src下建立com.test.simplefactory包,首先是抽象产品角色,比如人,定义一个接口Person.java:

    package com.test.simplefactory;
    
    public interface Person
    {
    	public String sayHello(String name);
    	
    	public String sayGoodbye(String name);
    }
    

    下面定义中国人和美国人这样两个具体产品角色:

    定义一个实现了Person接口的Chinese类:

    package com.test.simplefactory;
    
    public class Chinese implements Person
    {
    
    	@Override
    	public String sayGoodbye(String name)
    	{
    		return "再见, " + name;
    	}
    
    	@Override
    	public String sayHello(String name)
    	{
    		return "你好, " + name;
    	}
    
    }
    

    然后是实现了Person接口的American类:

    package com.test.simplefactory;
    
    public class American implements Person
    {
    
    	@Override
    	public String sayGoodbye(String name)
    	{
    		return "good bye, " + name;
    	}
    
    	@Override
    	public String sayHello(String name)
    	{
    		return "hello, " + name;
    	}
    
    }
    

    按照以前的方式,在不使用工厂类的情况下,我们编写客户端Client类如下:

    package com.test.simplefactory;
    
    public class Client
    {
    	public static void main(String[] args)
    	{
    		Person chinese = new Chinese();
    		
    		System.out.println(chinese.sayHello("张三"));
    		System.out.println(chinese.sayGoodbye("张三"));
    		
    		Person american = new American();
    		
    		System.out.println(american.sayHello("Tom"));
    		System.out.println(american.sayGoodbye("Tom"));
    	}
    }
    

    运行Client.java,输出如下:

    你好, 张三
    再见, 张三
    hello, Tom
    good bye, Tom
    

    下面,我们来分析一下这个程序有哪些不足的地方:客户端与具体实现类强耦合在一起,具体实现类增加、删除、修改了,客户端类都要随之发生变化。下面我们看看如何用工厂模式完成同样的功能。

    新建一个PersonFactory类:

    package com.test.simplefactory;
    
    public class PersonFactory
    {
    	public Person getPerson(String name)
    	{
    		if("american".equals(name))
    		{
    			return new American();
    		}
    		else if("chinese".equals(name))
    		{
    			return new Chinese();
    		}
    		else
    		{
    			return null;
    		}
    	}
    		
    		
    }
    

    如此以来,客户端Client就可以这样写了:

    package com.test.simplefactory;
    
    public class Client
    {
    	public static void main(String[] args)
    	{
    		PersonFactory factory = new PersonFactory();
    		
    		Person chinese = factory.getPerson("chinese");
    		
    		System.out.println(chinese.sayHello("张三"));
    		System.out.println(chinese.sayGoodbye("张三"));
    		
    		
    		Person american = new American();
    		
    		System.out.println(american.sayHello("Tom"));
    		System.out.println(american.sayGoodbye("Tom"));
    		
    	}
    }
    

    这样做的话,我们的客户端已经和具体的实现类没有强耦合这样的关系了,完全被工厂所掩盖了。这就是Spring IoC(Inverse of Control,控制反转)/DI(Dependency Injection,依赖注入)的基础。

    接下来,我们用Spring重现这个过程:新建一个Java Project:命名为Spring1。

    MyEclipse同样提供了对Spring的支持,src->MyEclipse->Add Spring Capabilities,选择Spring version版本号为Spring2.5,点击Next,去掉Enable AOP Builder前的勾勾,点击Finish。此时src包下便多了一个Spring相关的配置文件:applicationContext.xml。

    在src下面新建包:com.test,将simplefactory下的American、Chinese、Person这三个类拷贝到其下。接下来我们利用Spring作为工厂,实现相应的功能。

    在applicationContext.xml中配置如下信息:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans
    	xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:p="http://www.springframework.org/schema/p"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
    	<bean id="chinese" class="com.test.Chinese"></bean>
    	<bean id="american" class="com.test.American"></bean>
    
    </beans>
    

    然后新建一个Client类:

    package com.test;
    
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    
    public class Client
    {
    	public static void main(String[] args)
    	{
    		ClassPathResource cpr = new ClassPathResource("applicationContext.xml");
    		
    		XmlBeanFactory factory = new XmlBeanFactory(cpr);
    	
    		Person chinese = (Person)factory.getBean("chinese");
    		
    		System.out.println(chinese.sayHello("张三"));
    		System.out.println(chinese.sayGoodbye("张三"));
    	}
    }
    

    运行可以得到和之前simplefactory项目相同的结果,这样我们就通过Spring实现了控制反转(IoC/DI)。

    现在对Spring我们可以说有了一些初步的认识,接下来我们看一些更复杂的例子,看看Spring为我们提供了哪些强大的功能。

    如前步骤,新建Java项目Spring2,新建com.test包。下面我们常识使用Spring提供的依赖注入:对象依赖的其他属性由Spring自动帮我们生成好。

    在该包下面建立接口类Person:

    package com.test;
    
    public interface Person
    {
    	public void work();
    }
    

    人工作需要借助工具来完成,因此我们写一个接口类Tool:

    package com.test;
    
    public interface Tool
    {
    	public void realWork();
    }
    

    下面是工具的两个实现类ConcreteToolA和ConcreteToolB:

    package com.test;
    
    public class ConcreteToolA implements Tool
    {
    	@Override
    	public void realWork()
    	{
    		System.out.println("realwork from ConcreteToolA");
    	}
    	
    }
    
    ----------------------------------------------------------------------------------------------
    package com.test;
    
    public class ConcreteToolB implements Tool
    {
    	@Override
    	public void realWork()
    	{
    		System.out.println("realwork from ConcreteToolB");
    	}
    	
    }
    

    然后是实现了Person类的Chinese类:

    package com.test;
    
    public class Chinese implements Person
    {
    	private Tool tool;
    	
    	public void setTool(Tool tool)
    	{
    		this.tool = tool;
    	}
    	
    	public Tool getTool()
    	{
    		return tool;
    	}
    	
    	@Override
    	public void work()
    	{
    		tool.realWork();
    	}
    }
    

    如果不借助Spring的话Client编码如下:

    package com.test;
    
    public class Client
    {
    	public static void main(String[] args)
    	{
    		Chinese chinese = new Chinese();
    		
    		Tool tool = new ConcreteToolA(); // Tool tool = new ConcreteToolB();
    		
    		chinese.setTool(tool);
    		
    		chinese.work();
    	}
    }
    

    客户端与人和工具耦合,给我们带来了许多不便之处。接下来我们看看如何用Spring把这些耦合统统给去除掉。

    在applicationContext.xml中配置如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans
    	xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:p="http://www.springframework.org/schema/p"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
    	<bean id="toolA" class="com.test.ConcreteToolA"></bean>
    	<bean id="toolB" class="com.test.ConcreteToolB"></bean>
    
    	<bean id="chinese" class="com.test.Chinese">
    		<property name="tool" ref="toolA"></property>
    	</bean>
    </beans>
    

    客户端Client:

    package com.test;
    
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    
    public class Client
    {
    	public static void main(String[] args)
    	{
    		ClassPathResource cpr = new ClassPathResource("applicationContext.xml");
    		
    		XmlBeanFactory factory = new XmlBeanFactory(cpr);
    		
    		Person p = (Person)factory.getBean("chinese");
    				
    		p.work();
    	}
    }
    

    照样能够得到输出:real work from ConcreteToolA。

    MyEclipse操作补充:当配置文件很大的时候,如何快速浏览bean之间的依赖关系:Window->Show View->Spring Explorer。在列出的Spring项目中的applicationContext.xml上点击右键->Open Graph。即可以图形化的形式浏览各个bean之间的关系,比如Spring2项目下的bean之间的依赖关系:

    补充:对于Spring2项目来说,就像Struts的Action一样,对于每一个属性我们要为其提供对应的get和set方法,对于Spring来说,如果一个类里面有属性,那么我们至少要为这个属性提供一个set方法,让Spring根据配置文件中指定的依赖关系通过调用set方法的方式设置到对应的成员变量上。

  • 相关阅读:
    nat下没法ping通virutalbox中的centos7,解决共享文件夹问题
    深度学习的精确率和召回率,浅显的例子
    python发送邮件心得体会
    ubuntu 16.04 搭建tigervnc
    交叉编译7zip过程
    git使用经验汇总
    python 开发环境部署
    Ubuntu设置su和sudo为不需要密码 (摘录自别处)
    ubuntu 16.04 安装wechat, chrome等
    andorid开发build.gradle 增加几种产品的方法
  • 原文地址:https://www.cnblogs.com/Code-Rush/p/4864954.html
Copyright © 2020-2023  润新知