Spring实现两种设计模式:工厂模式和单态模式
2013-06-15 16:35
567 查看
工厂模式可将Java 对象的调用者从被调用者的实现逻辑中分离出来,调用者只需关心被调用者必须满足的规则(接口) ,而不必关心实例的具体实现过程。这是面向接口编程的优势,能提高程序的解耦,避免所有的类以硬编码方式耦合在一起。
如果所有的类直接耦合,极易形成"骨牌效应",假如B 类调用了A 类,一旦A 类需要修改,则B 类也需要修改;假如C 类调用了B 类,则C 类也需要修改......依次类推,从而导致整个系统都需要改写。造成"牵一发而动全身",而系统重构的代价是相当高的。
Spring 倡导”面向接口编程“,可以避免上述的问题,使设计良好的架构可保证系统重构的工作被封闭在重构的层内,绝不会影响其他层。
Spring 容器是实例化和管理全部bean 的工厂,Spring 默认将所有的bean 设置成单态模式,无须自己完成单态模式,即对所有相同id 的bean 请求都将返回同一个共享实例。因此,单态模式可大大降低Java 对象在创建和销毁时的系统开销。
一. 单态模式的回顾
单态模式限制了类实例的创建,但采用这种模式设计的类,可以保证仅有一个实例,并可提供访问该实例的全局访问点。J2EE应用的大量组件,都需要保证一个类只有一个实例。比如数据库引擎访问点只能有一个。
更多的时候,为了提高性能,程序应尽量减少Java 对象的创建和销毁时的开销。使用单态模式可避免Java 类被多次实例化,让相同类的全部实例共享同一内存区。
为了防止单态模式的类被多次实例化,应将类的构造器设成私有,这样就保证了只能通过静态方法获得类实例。而该静态方法则保证每次返回的实例都是同一个,这就需将该类的实例设置成类属性,由于该属性需要被静态方法访问,因此该属性应设成静态属性。
下面给出单态模式的示例代码:
从程序最后的打印结果可以看出,该类的两个实例完全相同。这证明单态模式类的全部实例是同一共享实例。程序里虽然获得了类的两个实例,但实际上只执行一次构造器,因为对于单态模式的类,无论有多少次的创建实例请求,都只执行一次构造器。
二. 工厂模式的回顾
工厂模式是根据调用数据返回某个类的一个实例,此类可以是多个类的某一个类。通常,这些类满足共同的规则(接口)或父类。调用者只关心工厂生产的实例是否满足某种规范,即实现的某个接口是否可供自己正常调用(调用者仅仅使用)。该模式给对象之间作出了清晰的角色划分,降低程序的耦合。
接口产生的全部实例通常用于实现相同接口,接口里定义了全部实例共同拥有的方法,这些方法在不同的实现类中实现的方式不同。从而使程序调用者无须关心方法的具体实现,降低了系统异构的代价。
下面是工厂模式的示例代码:
该接口定义了Person规范,规范要求实现该接口的类必须具有以下两个的方法:能打招呼,能告别。
下面是Person类的另一个实现类:Chinese
然后再看Person工厂的代码:
以上是最简单的工厂模式框架,其主程序如下:
由此可看出,主程序从Person 接口的具体类中解耦出来,而且程序调用者无须关心Person 的实例化过程,主程序仅仅与工厂服务定位结合在一起,可获得所有工厂能产生的实例。具体类的变化,接口无须发生任何改变,调用者程序代码部分也无须发生任何改动。
下面是Spring 对这两种模式的实现。
三. Spring 对单态与工厂模式的实现
随着Spring 提供工厂模式的实现,在使用Spring 时,无须自己提供工厂类。因为Spring容器是最大的工厂,而且是个功能超强的工厂。Spring 使用配置文件管理所有的bean ,其配置文件中bean 由Spring 工厂负责生成和管理。
下面是关于两个实例的配置文件:
主程序部分如下:
使用Spring 时,即使没有工厂类PersonFactory ,程序一样可以使用工厂模式, Spring完全可以提供所有工厂模式的功能。
下面对主程序部分进行简单的修改:
程序的执行结果是:true
表明Spring对接受容器管理的全部的bean,默认采用单态模式管理,建议不要随意更改bean的行为方式。因为从性能上讲,单态的bean比非单态的bean性能更为优秀。
仔细检查上面的代码就会发现如下的特点;
(1)除测试部分的主程序外,代码并未出现Spring的特定类和接口。
(2)调用者的代码,也就是测试用的主程序部分,仅仅面向Person的接口编程,而无需知道实现类的具体名称。同时,通过修改配置文件来彻底切换底层的具体实现类。
(3)由于厂无需多个实例,因此工厂应该采用单态模式设计,其中Spring上下文也就是Spring工厂,已被设计成单态。
Spring工厂模式,不仅提供了创建bean的功能,还提供了对bean的生命周期的管理。最重要的是还以管理bean和bean之间的依赖关系
如果所有的类直接耦合,极易形成"骨牌效应",假如B 类调用了A 类,一旦A 类需要修改,则B 类也需要修改;假如C 类调用了B 类,则C 类也需要修改......依次类推,从而导致整个系统都需要改写。造成"牵一发而动全身",而系统重构的代价是相当高的。
Spring 倡导”面向接口编程“,可以避免上述的问题,使设计良好的架构可保证系统重构的工作被封闭在重构的层内,绝不会影响其他层。
Spring 容器是实例化和管理全部bean 的工厂,Spring 默认将所有的bean 设置成单态模式,无须自己完成单态模式,即对所有相同id 的bean 请求都将返回同一个共享实例。因此,单态模式可大大降低Java 对象在创建和销毁时的系统开销。
一. 单态模式的回顾
单态模式限制了类实例的创建,但采用这种模式设计的类,可以保证仅有一个实例,并可提供访问该实例的全局访问点。J2EE应用的大量组件,都需要保证一个类只有一个实例。比如数据库引擎访问点只能有一个。
更多的时候,为了提高性能,程序应尽量减少Java 对象的创建和销毁时的开销。使用单态模式可避免Java 类被多次实例化,让相同类的全部实例共享同一内存区。
为了防止单态模式的类被多次实例化,应将类的构造器设成私有,这样就保证了只能通过静态方法获得类实例。而该静态方法则保证每次返回的实例都是同一个,这就需将该类的实例设置成类属性,由于该属性需要被静态方法访问,因此该属性应设成静态属性。
下面给出单态模式的示例代码:
package ppp; //单态模式测试类 public class SingletonTest { //该类的一个普通属性 int value; //使用静态属性保存该类的一个实例 private static SingletonTest instance; //构造器私有化,避免该类被多次实例化 private SingletonTest(){ System.out.println("正在执行构造器..."); } //提供静态方法返回该类实例 public static SingletonTest getInstance(){ //实例化类实例前,先检查该实例是否存在 if(instance == null){ //如果不存在,则新建一个实例 instance = new SingletonTest(); } //返回该类的成员变量:该类的实例 return instance; } //以下提供对普通属性value的getter和setter方法 public int getValue(){ return value; } public void setValue(int values){ this.value = values; } public static void main(String args[]){ SingletonTest t1 = SingletonTest.getInstance(); SingletonTest t2 = SingletonTest.getInstance(); t2.setValue(9); System.out.println(t1 == t2); } }
从程序最后的打印结果可以看出,该类的两个实例完全相同。这证明单态模式类的全部实例是同一共享实例。程序里虽然获得了类的两个实例,但实际上只执行一次构造器,因为对于单态模式的类,无论有多少次的创建实例请求,都只执行一次构造器。
二. 工厂模式的回顾
工厂模式是根据调用数据返回某个类的一个实例,此类可以是多个类的某一个类。通常,这些类满足共同的规则(接口)或父类。调用者只关心工厂生产的实例是否满足某种规范,即实现的某个接口是否可供自己正常调用(调用者仅仅使用)。该模式给对象之间作出了清晰的角色划分,降低程序的耦合。
接口产生的全部实例通常用于实现相同接口,接口里定义了全部实例共同拥有的方法,这些方法在不同的实现类中实现的方式不同。从而使程序调用者无须关心方法的具体实现,降低了系统异构的代价。
下面是工厂模式的示例代码:
package ppp; //Person接口定义 public interface Person { public String sayHello(String name); public String sayGoodbye(String name); }
该接口定义了Person规范,规范要求实现该接口的类必须具有以下两个的方法:能打招呼,能告别。
package ppp; //American类实现Person接口 public class American implements Person { public String sayHello(String name){ return name+",hello"; } public String sayGoodbye(String name) { return name+",goodbye"; } }
下面是Person类的另一个实现类:Chinese
package ppp; //Chinese类实现Person接口 public class Chinese implements Person { public String sayHello(String name){ return name+",您好"; } public String sayGoodbye(String name) { return name+",下次再见"; } }
然后再看Person工厂的代码:
package ppp; public class PersonFactory { public Person getPerson(String ethnic) { if(ethnic.equalsIgnoreCase("chin")) { return new Chinese(); }else{ return new American(); } } }
以上是最简单的工厂模式框架,其主程序如下:
package ppp; public class FactoryTest { public static void main(String[] args){ //创建PersonFactory实例 ,获得工厂实例 PersonFactory pf = new PersonFactory(); //定义接口Person实例,面向接口编程 Person p = null; //使用工厂获得person实例 p = pf.getPerson("chin"); //下面调用Person接口方法 System.out.println(p.sayHello("wawa")); System.out.println(p.sayGoodbye("wawa")); //使用工厂获得Person的另一个实例 p = pf.getPerson("ame"); //再次调用Person接口的方法 System.out.println(p.sayHello("wawa")); System.out.println(p.sayGoodbye("wawa")); } }
由此可看出,主程序从Person 接口的具体类中解耦出来,而且程序调用者无须关心Person 的实例化过程,主程序仅仅与工厂服务定位结合在一起,可获得所有工厂能产生的实例。具体类的变化,接口无须发生任何改变,调用者程序代码部分也无须发生任何改动。
下面是Spring 对这两种模式的实现。
三. Spring 对单态与工厂模式的实现
随着Spring 提供工厂模式的实现,在使用Spring 时,无须自己提供工厂类。因为Spring容器是最大的工厂,而且是个功能超强的工厂。Spring 使用配置文件管理所有的bean ,其配置文件中bean 由Spring 工厂负责生成和管理。
下面是关于两个实例的配置文件:
<!--下面是xml文件的文件头--> <?xml version = "1.0" encoding = "gb2312"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springsource.org/dtd/spring-beans.dtd"> <!--beans是Spring配置文件的根元素--> <beans> <!--定义第一个bean,该bean的id是chinese--> <bean id = "chinese" class = "ppp.Chinese"/> <!--定义第二个bean,该bean的id是American--> <bean id = "american" class = "ppp.American"/> </beans>
主程序部分如下:
package ppp; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class SpringTest { public static void main(String[] args) { //实例化Spring容器 ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml"); //定义Person接口实例 Person p = null; //通过Spring上下文获得Chinese实例 p = (Person)ctx.getBean("chinese"); //执行chinese实例的方法 System.out.println(p.sayHello("wawa")); System.out.println(p.sayGoodbye("wawa")); p = (Person)ctx.getBean("american"); System.out.println(p.sayHello("wawa")); System.out.println(p.sayGoodbye("wawa")); } }
使用Spring 时,即使没有工厂类PersonFactory ,程序一样可以使用工厂模式, Spring完全可以提供所有工厂模式的功能。
下面对主程序部分进行简单的修改:
package ppp; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class SpringTest{ public static void main(String[] args){ //实例化Spring容器 ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml"); //定义p1接口的实例p1 Person p1 = null; //通过Spring上下文获得Chinese实例 p1 = (Person)ctx.getBean("Chinese"); //定义p2接口的实例p2 Person p2 = null; p2 = (Person)ctx.getBean("Chinese"); System.out.println(p1 == p2); } }
程序的执行结果是:true
表明Spring对接受容器管理的全部的bean,默认采用单态模式管理,建议不要随意更改bean的行为方式。因为从性能上讲,单态的bean比非单态的bean性能更为优秀。
仔细检查上面的代码就会发现如下的特点;
(1)除测试部分的主程序外,代码并未出现Spring的特定类和接口。
(2)调用者的代码,也就是测试用的主程序部分,仅仅面向Person的接口编程,而无需知道实现类的具体名称。同时,通过修改配置文件来彻底切换底层的具体实现类。
(3)由于厂无需多个实例,因此工厂应该采用单态模式设计,其中Spring上下文也就是Spring工厂,已被设计成单态。
Spring工厂模式,不仅提供了创建bean的功能,还提供了对bean的生命周期的管理。最重要的是还以管理bean和bean之间的依赖关系
相关文章推荐
- Spring 实现两种设计模式:工厂模式和单态模式
- Spring 实现两种设计模式
- [设计模式]两种方法实现简单工厂模式
- Spring 实现两种设计模式
- Spring实现的两种设计模式
- 基于配置文件的工厂设计模式实现,并且做到对象的单例,类似于spring的ioc
- 两种设计模式(1)==>>“简单工厂”
- 设计模式之工厂模式 Factory实现
- 设计模式C++实现(1)——工厂模式
- 六种常用的设计模式java实现(一)工厂模式
- 设计模式C++实现(1)——工厂模式
- Java设计模式之工厂模式(利用反射实现)
- 从Spring HibernateTemplate模板方法设计模式的实现谈起
- 设计模式之单例模式与工厂模式的Python实现(一)
- 23种设计模式之python实现--工厂方法
- C++实现设计模式: Factory 工厂模式
- [Java] 设计模式之工厂系列 04 (自定义模拟 spring 读取xml文件 beanFactory)
- 设计模式实践-反射到所有接口实现类实践工厂方法,页面中有大量计算数据时设计实践
- 设计模式C++实现(1)——工厂模式
- 设计模式C++实现(1)——工厂模式