创建对象_工厂方法(Factory Method)模式 与 静态工厂方法

摘要:
使用构造函数实例化对象是语言的规范,静态工厂方法与其他静态方法没有区别,这增加了用户使用的差异。静态工厂方法可以突破构造函数不能自由命名的限制,不同的工厂方法可以用不同的含义命名。
 

工厂方法模式:

 
定义:为创建对象定义一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟至子类。
 
应用场景
  • 客户类不关心使用哪个具体类,只关心该接口所提供的功能;
  • 创建过程比较复杂,例如需要初始化其他关联的资源类,读取配置文件等;
  • 接口有很多具体实现或者抽象有很多具体子类时,你可能需要为客户代码写一大串 if-else 逻辑来决定运行时使用哪个具体实现或者具体子类;
  • 不希望给客户程序暴露过多此类的内部结构,隐藏这些细节可以降低耦合度;
  • 优化性能,比如缓存大对象或者初始化比较耗时的对象。
 
 
 
工厂方法模式
 
//工厂接口定义了 createProduct()方法来放回 Product 类型的实例对象
public interface Factory {
 
    // 如果具体实现较多,定义一个参数化的工厂方法,根据不同的参数返回不同的子类
    Product createProduct(String type);
}
 
//工厂接口实现类
public class ConcreteFactory implements Factory {
 
    // 如果具体实现较多,定义一个参数化的工厂方法,根据不同的参数返回不同的子类
    @Override
    public Product createProduct(String type) {
        if ("type1".equals(type)) {
            return new ConcreteProduct1();
        } else if ("type2".equals(type)) {
            return new ConcreteProduct2();
        } else {
            return new ConcreteProduct3();
        }
    }
}
 
//定义产品统一接口
public interface Product {
 
}
//不同的产品实现
public class ConcreteProduct1 implements Product {
 
}
public class ConcreteProduct2 implements Product {
 
}
public class ConcreteProduct3 implements Product {
 
}
 
    客户类通过工厂得到产品实例:
public class Client {
 
    private Factory factory;
 
    public Client(Factory factory) {
        this.factory = factory;
    }
 
    public void dosomething(String type) {
        Product product = factory.createProduct(type);
        // to do something
    }
 
    public static void main(String[] args) {
        // 实例化工厂
        Client client = new Client(new ConcreteFactory());
        // 传入参数给工厂得到指定的产品实例
        client.dosomething("type1");
    }
}

静态工厂方法:

 
应用场景:工厂模式为每个类创建一个工厂方法 方法类会引起工厂类的泛滥。
 
解决方案:使用静态工厂方法来避免——在每个类里实现一个静态的工厂方法,就不再需要额外的工厂类。
 
静态工厂方法的优缺点
  • 优点:
    • 可以为静态工厂选择合适的命名,提高程序的可读性。
    • 静态工厂和工厂模式一样,可以封装复杂的初始化过程,实现实例的缓存。
    • 还可以根据不同的输入返回不同实现类/具体类对象。
  • 缺点:
    • 一般为了强迫使用工厂方法,不直接使用构造方法来构造实例,我们会强迫类只含有私有或是default的构造方法,这样,会导致此类不能被子类化。
    • 如果添加了一个新的该类的子类(该类有非私有的构造方法),此静态工厂方法可能需要重写,以加入该子类的实例化过程,导致扩展性不强。
    • 静态方法没有面向对象的特征,比如继承、动态多态等,不可被覆写(Overwritten)。
    • 采用构造函数实例化对象,是语言的规范,而静态工厂方法与其他的静态方法没有区别,就增加了用户使用的区别。但这可以尽量采用一些家喻户晓的名字解决,让用户看到改名字就知道该方法是静态工厂方法。如getInstance( )。
    • 静态工厂方法代表了一种对规范的背离。
 
    创建类的实例最常见的是new 除此外还可以使用静态工厂方法,来封装实例的细节,并且能控制实例的数量,减轻 jvm的堆栈中的压力。
 
 
静态工厂方法与用 new语句调用的构造方法相比,有以下区别:
  • 使程序具有更好的可读性。静态工厂方法可以突破构造函数不能自由命名的限制,对于不同的工厂方法可以采用不同的会意的名字。JAVA平台库的java.text.Format的子类NumberFormat就有getInstance() , getPrecentInstance() , getCurrencyInstatnce()等静态方法,通过不同的名字产生特定的对象。
  • 加大了程序设计和使用的灵活行。静态工厂方法是用来产生对象用的,至于产生什么类型的对象没有限制,这就意味这只要返回原返回类型或原返回类型的子类型都可以;或者是否会创建一个新的对象完全取决于方法的实现。如java.util集合框架就采用了这种优势,这样就可以更好达到封装的目的,降低API的数目和用户的使用难度,java.util.Connections是集合框架的辅助类用于对原有的集合类进行进一步封装,产生一些同步的集合,不可修改的视图。都是采用静态工厂方法实现的,至于方法内部的实现类就完全别封装了。也迫使我们使用接口编程。
  • 解耦。静态工厂方法所创建的对象可以在编译时不存在,动态创建对象,采用反射,类似Spring 的 IOC容器方转。达到对象的创建与使用分离,使对象的客户和对象之间解耦,增加程序的灵活性和可扩展性。
    静态工厂方法最主要的特点是:每次被调用的时候,不一定要创建一个新的对象。利用这一特点,静态工厂方法可用来创建以下类的实例。
  • 单例类:只有惟一的实例的类。
  • 枚举类:实例的数量有限的类。
  • 具有实例缓存的类:能把已经创建的实例暂且存放在缓存中的类。
  • 具有实例缓存的不可变类:不可变类的实例一旦创建,其属性值就不会被改变。
 
所谓静态工厂方法(static factory method),实际上只是一个简单的静态方法,它返回的是类的一个实例。
public   static  Boolean  getTrue () {
     return  Boolean.TRUE;
}
 
总结:工厂模式把对象实例化的过程进行了封装,客户对象不必为实例化而考虑更多,分离了实例化的逻辑,使得对象间的耦合性大大降低。
 
 

免责声明:文章转载自《创建对象_工厂方法(Factory Method)模式 与 静态工厂方法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java利用SuffixFileFilter统计目录下特定后缀名文件的数目什么是形式验证?下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java中枚举的使用

常量与枚举 一、常量定义方法        常量是其值固定不变的量,一般可以分为字面常量和命名常量,如数字1,2,1.3,字符串“abc”,这些就是字面常量,而命名常量是我们使用一些有意义的名称来代表字面常量值,通常命名常量有助于我们更好地理解程序的逻辑。        在Java中,我们通常使用public static final ... 方式来定义常...

Thymeleaf入门到吃灰

Thymeleaf    官网部分翻译:反正就是各种好 Thymeleaf是用来开发Web和独立环境项目的服务器端的Java模版引擎 Spring官方支持的服务的渲染模板中,并不包含jsp。而是Thymeleaf和Freemarker等,而Thymeleaf与SpringMVC的视图技术,及SpringBoot的自动化配置集成非常完美,几乎没有任何成...

【Android】反射

package com.example.myandroidtest; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; impo...

Java 的类加载顺序

Java 的类加载顺序 一、加载顺序:先父类后子类,先静态后普通 1、父类的静态成员变量初始化 2、父类的静态代码块 3、子类的静态成员变量初始化 4、子类的静态代码块 5、父类的普通成员变量初始化 6、父类的普通代码块 7、父类的无参构造器 8、子类的普通成员变量 9、子类的普通代码块 10、子类的无参构造器 二、示例代码   超级父类A,父类B,子类C...

Java中类加载过程和对象创建过程

类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在。如果有,就直接使用;如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加载非静态内容,再加载静态内容 3, 加载非静态内容:把.class中的所有非静态内容加载到方法区下的非静态区域内 4, 加载静态内容:     4.1、把.c...

java中子类继承父类程序执行顺序问题

Java中,new一个类的对象,类里面的静态代码块、非静态代码、无参构造方法、有参构造方法、类的一般方法等部分,它们的执行顺序相对来说比较简单,用程序也很容易验证。比如新建一个测试父类。 publicclassFatherTest { privateString name; FatherTest(){ System.out.println("--父类的无参...