【前面的话】

每天过的还行,对我来说,只要让自己充实,生活就会是好的。

学习Java工场方法的原因是最近在使用Spring框架做一个系统,其中有一个注入的方法是使用静态工场方法注入,所以学习一下,基础性文章,选择性阅读。

      这篇文章学习的是静态工厂。

【什么是】

一、定义

     工厂:在面向对象程序设计中,工厂通常是一个用来创建其他对象的对象。工厂是构造方法的抽象,用来实现不同的分配方案。

     工厂方法模式(英语:Factory method pattern)是一种实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。”

二、举例

工厂模式是根据不同的参数创建对象。例如用工厂创建小汽车。 如果我们想要一辆奥迪,工厂就会为我们生产一辆奥迪;如果我们需要一辆宝马,工厂则会为我们生产一辆宝马。工厂会根据不同的参数,为我们提供不同的物品。而这些创建的过程就是实例化,也就是是说,对对象实例化的过程封装起来,专门建立一个类进行实例化,这就是工厂模式。

【怎么做】

从下面两段关键代码来看,没有使用静态工厂的代码使得Manager类和具体的实现类紧耦合,如果生产的汽车种类繁多的话,Manager会经常变化,使得Manager类会经常修改,而使用了静态工厂的代码,将所有的实例化都封装在一个工厂类中,以后可能不光是Manager这个类可以调用工厂类,增加的别的方法也是可以调用工厂了。

一、没有使用静态工厂的代码:

1. Manager.java

 public class Manager {
public static Car CreatCar(String type){
Car car = null;//Manager与Audi类和BaoMa类还有Suv类耦合,进行了硬编码
if(type.equals("audi")){
car=new AuDi();
}else if(type.equals("baoma")){
car=new BaoMa();
}else if(type.equals("suv")){
car=new Suv();
}
car.Prepare();
car.Install();
car.Color();
return car;
}
}

二、使用静态工厂的代码:

1. Manager.java

 public class Manager {
Car car = null;
public Car CreatCar(String type){//Manager类和具体类解耦合,不需要关心具体的类的实现方法。
car=CarFactory.getCarInstance(type);//静态方法,不需要使用创建工厂CarFactory来创建对象,直接使用CarFactory来调用其方法。
car.Prepare();
car.Install();
car.Color();
return car;
}
}

2. CarFactory.java

 public class CarFactory {
public static Car getCarInstance(String type){//静态方法,这样做的缺点是如果CarFactory被继承,getCar不能被重写。
Car carInstance = null;
if(type.equals("audi")){
carInstance=new AuDi();
}else if(type.equals("baoma")){
carInstance=new BaoMa();
}else if(type.equals("suv")){
carInstance=new Suv();
}
return carInstance;
}
}

【为什么】

为什么要使用静态工厂模式,这样做的好处如下几点:

第一:静态工厂方法可以突破构造函数不能自由命名的限制,对于不同的工厂方法可以采用不同的会意的名字,是程序具有更好的可读性。JAVA平台库的java.text.Format的子类NumberFormat就有getInstance() , getPrecentInstance() , getCurrencyInstatnce()等静态方法,通过不同的名字产生特定的对象。

第二:静态工厂方法是用来产生对象用的,至于产生什么类型的对象没有限制,这就意味这只要返回原返回类型或原返回类型的子类型都可以,这样就加大了程序设计和使用的灵活行,如java.util集合框架就采用了这种优势,这样就可以更好达到封装的目的,降低API的数目和用户的使用难度,java.util.Connections是集合框架的辅助类用于对原有的集合类进行进一步封装,产生一些同步的集合,不可修改的视图。都是采用静态工厂方法实现的,至于方法内部的实现类就完全别封装了。也迫使我们使用接口编程。

第三:静态工厂方法所创建的对象可以在编译时不存在,动态创建对象,采用放射,类似SPRING的IOC容器方转。最典型的例子就是spi服务提供者框架,Service Provider Iframe 是一种用于在运行时刻产生对象的框架,达到对象的创建与使用分离,是对象的客户和对象之间解耦,增加程序的灵活性和可扩展性。既然spi可以动态创建对象,那么采用什么机制来创建什么对象,创建对象的依据是什么了,spi必须一种统一的注册机制,对于要创建的对象,应该在XML文件中配置,到时候,只要提供一个字符串,就可以凭借该字符串来创建配置的对象

【缺点】

  1. 静态方法,这样做的缺点是如果CarFactory被继承,getCar不能被重写。
  2. 因为我们一般都采用的是构造函数进行实例化对象,而采用静态工厂的方法进行实例化就会使得实例化和构造函数实例化不一样,所以增加了使用难度,一般都要采用较为清晰的命名,使得使用者可以一目了然知道使用了静态方法。
  3. 如果例子中某一个具体类的构造函数式私有,就会出现错误。

【代码举例】

下面记录了两个代码demo,一个是没有使用静态工厂方法的demo,一个是使用了静态工厂方法的demo。

一、不是用静态工厂模式的代码

1. AuDi.java

 public class AuDi implements Car {
public void Prepare(){
System.out.println("我是奥迪车,我在进行生产准备");
}
public void Install(){
System.out.println("我是奥迪车,我在进行组装");
}
public void Color(){
System.out.println("我是奥迪车,我在进行着色");
}
}

2. BaoMa.java

 public class BaoMa implements Car{
public void Prepare(){
System.out.println("我是宝马车,我在进行生产准备");
}
public void Install(){
System.out.println("我是宝马车,我在进行组装");
}
public void Color(){
System.out.println("我是宝马车,我在进行着色");
}
}

3. Suv.java

 public class Suv implements Car{
public void Prepare(){
System.out.println("我是SUV车,我在进行生产准备");
}
public void Install(){
System.out.println("我是SUV车,我在进行组装");
}
public void Color(){
System.out.println("我是SUV车,我在进行着色");
}
}

4. Car.java

 public interface Car {
public abstract void Prepare();
public abstract void Install();
public abstract void Color();
}

5. Manager.java

 public class Manager {
public static Car CreatCar(String type){
Car car = null;//Manager与Audi类和BaoMa类还有Suv类耦合,进行了硬编码
if(type.equals("audi")){
car=new AuDi();
}else if(type.equals("baoma")){
car=new BaoMa();
}else if(type.equals("suv")){
car=new Suv();
}
car.Prepare();
car.Install();
car.Color();
return car;
}
}

6. MainTest.java

 public class MainTest {
public static void main(String[] args){
Manager.CreatCar("audi");
Manager.CreatCar("baoma");
Manager.CreatCar("suv");
}
}

7. 运行结果:

 我是奥迪车,我在进行生产准备
我是奥迪车,我在进行组装
我是奥迪车,我在进行着色
我是宝马车,我在进行生产准备
我是宝马车,我在进行组装
我是宝马车,我在进行着色
我是SUV车,我在进行生产准备
我是SUV车,我在进行组装
我是SUV车,我在进行着色

二、使用静态工厂模式的代码

1. AuDi.java

 public class AuDi implements Car {
public void Prepare(){
System.out.println("我是奥迪车,我在进行生产准备");
}
public void Install(){
System.out.println("我是奥迪车,我在进行组装");
}
public void Color(){
System.out.println("我是奥迪车,我在进行着色");
}
}

2. BaoMa.java

 public class BaoMa implements Car{
public void Prepare(){
System.out.println("我是宝马车,我在进行生产准备");
}
public void Install(){
System.out.println("我是宝马车,我在进行组装");
}
public void Color(){
System.out.println("我是宝马车,我在进行着色");
}
}

3. Suv.java

 public class Suv implements Car{
public void Prepare(){
System.out.println("我是SUV车,我在进行生产准备");
}
public void Install(){
System.out.println("我是SUV车,我在进行组装");
}
public void Color(){
System.out.println("我是SUV车,我在进行着色");
}
}

4. Car.java

 public interface Car {
public abstract void Prepare();
public abstract void Install();
public abstract void Color();
}

5. Manager.java

 public class Manager {
Car car = null;
public Car CreatCar(String type){//Manager类和具体类解耦合,不需要关心具体的类的实现方法。
car=CarFactory.getCarInstance(type);//静态方法,不需要使用创建工厂CarFactory来创建对象,直接使用CarFactory来调用其方法。
car.Prepare();
car.Install();
car.Color();
return car;
}
}

6.CarFactory.java

 public class CarFactory {
public static Car getCarInstance(String type){//静态方法,这样做的缺点是如果CarFactory被继承,getCar不能被重写。
Car carInstance = null;
if(type.equals("audi")){
carInstance=new AuDi();
}else if(type.equals("baoma")){
carInstance=new BaoMa();
}else if(type.equals("suv")){
carInstance=new Suv();
}
return carInstance;
}
}

7.MainTest.java

 public class MainTest {
public static void main(String[] args){
Manager manager=new Manager();
manager.CreatCar("audi");
manager.CreatCar("baoma");
manager.CreatCar("suv");
}
}

8.运行结果:

 我是奥迪车,我在进行生产准备
我是奥迪车,我在进行组装
我是奥迪车,我在进行着色
我是宝马车,我在进行生产准备
我是宝马车,我在进行组装
我是宝马车,我在进行着色
我是SUV车,我在进行生产准备
我是SUV车,我在进行组装
我是SUV车,我在进行着色

【资料下载】

代码demo下载:http://download.csdn.net/detail/xtbda/7096469

【参考资料】

  1. 讲故事,学(Java)设计模式—工厂模式  http://www.importnew.com/6718.html
  2. 工厂方法设计模式的最佳实践 http://www.importnew.com/10286.html
  3. 静态工厂方法http://blog.csdn.net/mingyunduoshou/article/details/6149758
  4. 《Head First设计模式》Eric Freeman&Elisabeth Freeman著

【后面的话】

好好学习,最近学习稍微显得有点乱,要有步骤,有计划。

——TT

Java学习笔记(十四)——Java静态工厂的更多相关文章

  1. Java学习笔记十四:如何定义Java中的类以及使用对象的属性

    如何定义Java中的类以及使用对象的属性 一:类的重要性: 所有Java程序都以类class为组织单元: 二:什么是类: 类是模子,确定对象将会拥有的特征(属性)和行为(方法): 三:类的组成: 属性 ...

  2. Java学习笔记十八:Java面向对象的三大特性之封装

    Java面向对象的三大特性之封装 一:面向对象的三大特性: 封装 继承 多态   二:封装的概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访 ...

  3. Java学习笔记十五:Java中的成员变量和局部变量

    Java中的成员变量和局部变量 一:成员变量: 成员变量在类中定义,用来描述对象将要有什么 成员变量可以被本类的方法使用,也可以被其他类的方法使用,成员变量的作用域在整个类内部都是可见的 二:局部变量 ...

  4. Java 读书笔记 (十四) Java 方法

    finalize() 方法 finalize() 用来清除回收对象.  //为什么要回收内存?怎样写可以避免内存过多占用?什么时候需要手动回收内存? protected void finalize() ...

  5. Java学习笔记十九:Java中的访问控制修饰符

    Java中的访问控制修饰符 一:Java修饰符的种类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class Hello ...

  6. Java学习笔记十六:Java中的构造方法

    Java中的构造方法 1.使用new+构造方法 创建一个新的对象: 2.构造方法是定义在Java类中的一个用来初始化对象的方法: 3.构造方法与类同名且没有返回值: 4.语法格式: public 构造 ...

  7. Java学习笔记十二:Java中方法的重载

    Java中方法的重载 什么是方法的重载呢? 如果同一个类中包含了两个或两个以上方法名相同.方法参数的个数.顺序或类型不同的方法,则称为方法的重载,也可称该方法被重载了.如下所示 4 个方法名称都为 s ...

  8. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  9. 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类

    static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...

  10. Java学习笔记心得——初识Java

    初识Java 拿到这本厚厚的<Java学习笔记>,翻开目录:Java平台概论.从JDK到TDE.认识对象.封装.继承与多态...看着这些似懂非懂的术语名词,心里怀着些好奇与担忧,就这样我开 ...

随机推荐

  1. Emmet缩写语法

    缩写语法 Emmet 使用类似于 CSS 选择器的语法描述元素在生成的文档树中的位置及其属性. 元素 可以使用元素名(如 div 或者 p)来生成 HTML 标签.Emmet 没有预定义的有效元素名的 ...

  2. Java Web用Freemarker生成带图片的Word文档

    步骤一:模板制作 用world2003做一个导出模板,如果有图片则加入一张图片占位,将world另存为xml,将xml中需要导出的内容用Freemarker标签表示,最后另存为.ftl结尾的模板: 步 ...

  3. nginx基于域名的虚拟主机配置(本地分布式项目域名配置及测试方法)

    最有用的虚拟主机配置方式. 一个域名只能绑定一个ip地址,一个ip地址可以被多个域名绑定. 可以修改host文件实现域名访问. 前提:即使我们在nginx中配置基于域名的虚拟主机,也需要域名解析,即n ...

  4. HDU2121:Ice_cream’s world II (虚根+有向图最小生成树)

    Ice_cream’s world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  5. (转)python编码问题

    时不时总是会碰到令人头疼的编码问题,这里推荐一篇决定好文,需反复诵读之: http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html . . ...

  6. div模拟textarea在ios下不兼容的问题解决

    今天发现一个好东西,赶紧记下来,我在用textarea的时候,想要自适应高度,这样就不会出现滚动条.网上找了很多,都是用div模拟的,但是好扯淡,div模拟的在ios下不能聚焦并且不能输入.真坑... ...

  7. 数学:拓展BSGS

    当C不是素数的时候,之前介绍的BSGS就行不通了,需要用到拓展BSGS算法 方法转自https://blog.csdn.net/zzkksunboy/article/details/73162229 ...

  8. Spark的Shuffle过程介绍

    Spark的Shuffle过程介绍 Shuffle Writer Spark丰富了任务类型,有些任务之间数据流转不需要通过Shuffle,但是有些任务之间还是需要通过Shuffle来传递数据,比如wi ...

  9. web版canvas做飞机大战游戏 总结

    唠唠:两天的时间跟着做了个飞机大战的游戏,感觉做游戏挺好的.说是用html5做,发现全都是js.说js里一切皆为对象,写的最多的还是函数,都是函数调用.对这两天的代码做个总结,希望路过的大神指点一下, ...

  10. gradle web项目启动报错: java.lang.ClassNotFoundException: org.springframework.web.util.IntrospectorCleanupListener

    严重: Error configuring application listener of class org.springframework.web.util.IntrospectorCleanup ...