Effective 学习(1) ---- 静态工厂方法

来源:互联网 发布:nginx事件驱动模型 编辑:程序博客网 时间:2024/04/30 08:23

初读《EffectiveJava》考虑静态工厂方法代替构造函数中!始终看不懂他的结构图!也不能理解静态工厂模式的使用点!首先是真看不太懂,有些地方说是源码的某某处,没有具体的概念导致不是很明白,于是上网寻找资料。

网络上的解释:静态工厂并不是代替构造函数本身,而是代替了构造函数的调用,即替换到了new操作符,好处就是降低了类之间的耦合。假设类A中有 IB b = new B()这样的构造函数调用(其中B是接口IB的实现类),那么我们就称A依赖于B这个具体实现,那么A和B的耦合程度就高,如果B发生了变化,很有可能需要修改所有对B发生依赖的类。而工厂模式的出现就是为减低这种耦合,把对B的依赖从A转加到B的工厂方法里,比如:IB b = BF.getInstance();而BF将返回B的实例,当然这个B的实例也是通过B的构造函数生成的,这种情况下即使B发生了某些变化,我们期望另一个也同样实现IB接口的B‘来代替的时候,我们只需要修改BF这一个地方就可以了。


1.什么是静态工厂方法

其又叫简单工厂模式,与工厂模式不同,其是通过专门定义一个类来负责创建其他类的实例,其实例通常拥有共同父类,其普遍实现主要依靠Java的反射机制。和静态的方法表现是一样的,在方法前面加上 static. 存在一些惯用的名称 :valueof,getInstance,newInstance,getType,newType 等等。


2.优点的体现

Effective Java中共提到好处四点:

1、它们有名称
2、它们可以返回原返回类型任意子类型的对象。

  针对于第一点,相比较于与类名相同的构造函数,静态工厂方法是通过静态方法进行对象的初始化,其方法名字自然可以自定义,从而帮助开发人员的理解,这是容易理解的。例如:构造器BigInteger(int,int,Random)返回的BigInteger可能为素数,如果改名为 BigInteger.probablePrime的静态方法表示,显然更为清楚。
  
  对于第二点没看明白,摘自网络:
  第二点,其在Java中的集合类Collections用的颇多,主要利用Java的多态的特性,使得工厂可以产生基类的同时注入子类实现。如:

public interface Food {    /**     * 使得所有食物都有一个共有的introduce方法     */    public void introduce();}/** * 定义食物的子类:鱼 */public class Fish implements Food{    @Override    public void introduce() {        System.out.println("i am a fish");    }}/** * 食物的子类,水果 */public class Fruit implements Food {    @Override    public void introduce() {        System.out.println("i am the fruit");    }}/** * 通过反射机制实现的工厂 */public class FoodFactory {    public static Food getFood(String type) {        Food food = null;        try {            food = (Food) Class.forName("info.zhw." + type).newInstance();        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        return food;    }}

FoodFactory就利用了基类,返回了该类型的子类型。

3、不必在每次调用他们的时候都创建一次对象。

  这使得不可变类可以使用预先构建好的实例,或者将构建好的实例缓存起来,进行重复利用,从而避免了创建不必要的重复对象。Boolean.valueOf(boolean b)方法说明了这项技术,它从来不创建对象。

 /**     * Returns a {@code Boolean} instance for the specified boolean value.     * <p>     * If it is not necessary to get a new {@code Boolean} instance, it is     * recommended to use this method instead of the constructor, since it     * returns its static instances, which results in better performance.     *     * @param b     *            the boolean to convert to a {@code Boolean}.     * @return {@code Boolean.TRUE} if {@code b} is equal to {@code true},     *         {@code Boolean.FALSE} otherwise.     */    public static Boolean valueOf(boolean b) {        return b ? Boolean.TRUE : Boolean.FALSE;    }
 /**     * The {@code Boolean} object that represents the primitive value     * {@code true}.     */    public static final Boolean TRUE = new Boolean(true);    /**     * The {@code Boolean} object that represents the primitive value     * {@code false}.     */    public static final Boolean FALSE = new Boolean(false);

使用构造函数,调用其中的方法,则实例化一个类是必不可少的步奏,而是使用静态工厂方法,则可以对对象进行重复利用,这个特点在单例模式中使用颇多。其将构造方法私有,只能通过getInstance()获取实例,从而达到实例重复利用的目的。

4、使代码简洁

  与第一点有点雷同,主要也是在方便理解的基础上作出的改进。


3.缺点从何体现

1、如果类不含有公有或受保护构造器,就不能被子类化。
2、和静态方法实际上没有任何区别。其无法在API文档中明确标出,推荐使用管用名称管理。

下面是 静态工厂方法的一些惯用的名称:

valueof,getInstance,newInstance,getType,newType 等等

3、网上摘录的一段(http://blog.163.com/zhuowh2006@126/blog/static/10182372420133220511247/)

  由于工厂类集中了所有实例的创建逻辑,这就直接导致一旦这个工厂出了问题,所有的客户端都会受到牵连;而且由于简单工厂模式的产品室基于一个共同的抽象类或者接口,这样一来,但产品的种类增加的时候,即有不同的产品接口或者抽象类的时候,工厂类就需要判断何时创建何种种类的产品,这就和创建何种种类产品的产品相互混淆在了一起,违背了单一职责,导致系统丧失灵活性和可维护性。而且更重要的是,简单工厂模式违背了“开放封闭原则”,就是违背了“系统对扩展开放,对修改关闭”的原则,因为当我新增加一个产品的时候必须修改工厂类,相应的工厂类就需要重新编译一遍。


4.总结

  简而言之,静态工厂方法和公有构造齐都各有用处,我们需要理解她们各种的长处。静态工厂通常更加合适,因此切记第一反应就是提供公有的构造器,而不先考虑静态工厂。

参考地址:http://www.cnblogs.com/sluggard/p/4343426.html

0 0
原创粉丝点击