《java与模式》读书笔记之一----简单工厂模式

简单的说,简单工厂模式就是由一个工厂来决定创建出那一种产品类的的实例。这类产品必须都是有相同的父类或者接口。

所以列,它通常涉及到三个角色:

  • 工厂类:也是这个模式的核心,包含了所有的与对象创建相关的所有商业逻辑。
  • 抽象采品:通常是接口或者抽象类,是工厂类的返回值类型,是工厂类创建出的产品的父类或接口
  • 具体产品:继承或者实现抽象产品的具体产品。

他的特征除了以上三个角色以外,还有一个:工厂方法为static的,至于这点我们到后面来说。


典型的代码如下:

public class Factory{
  public static Product create(){
      //具体的创建逻
      return new  ConcreteProduct();
  }
}

public interface Product{}

public class ConcreteProduct implements Product{

}


接下来我们就来找找这个模式在Java API中的应用。书中提到了这么一个类:DateFormat.的三个getTimeInstance()方法,那么我们就进去看看源码。

 /**
     * Gets the time formatter with the default formatting style
     * for the default locale.
     * @return a time formatter.
     */
    public final static DateFormat getTimeInstance()
    {
        return get(DEFAULT, 0, 1, Locale.getDefault());
    }

    /**
     * Gets the time formatter with the given formatting style
     * for the default locale.
     * @param style the given formatting style. For example,
     * SHORT for "h:mm a" in the US locale.
     * @return a time formatter.
     */
    public final static DateFormat getTimeInstance(int style)
    {
        return get(style, 0, 1, Locale.getDefault());
    }

    /**
     * Gets the time formatter with the given formatting style
     * for the given locale.
     * @param style the given formatting style. For example,
     * SHORT for "h:mm a" in the US locale.
     * @param aLocale the given locale.
     * @return a time formatter.
     */
    public final static DateFormat getTimeInstance(int style,
                                                 Locale aLocale)
    {
        return get(style, 0, 1, aLocale);
    }

可以很明显的看出,这个三个方法都是调用了get()方法,那我们继续跟踪看一下具体实现:

 private static DateFormat get(int timeStyle, int dateStyle,
                                  int flags, Locale loc) {
        if ((flags & 1) != 0) {
            if (timeStyle < 0 || timeStyle > 3) {
                throw new IllegalArgumentException("Illegal time style " + timeStyle);
            }
        } else {
            timeStyle = -1;
        }
        if ((flags & 2) != 0) {
            if (dateStyle < 0 || dateStyle > 3) {
                throw new IllegalArgumentException("Illegal date style " + dateStyle);
            }
        } else {
            dateStyle = -1;
        }
        try {
            // Check whether a provider can provide an implementation that's closer 
            // to the requested locale than what the Java runtime itself can provide.
            LocaleServiceProviderPool pool =
                LocaleServiceProviderPool.getPool(DateFormatProvider.class);
            if (pool.hasProviders()) {
                DateFormat providersInstance = pool.getLocalizedObject(
                                                    DateFormatGetter.INSTANCE,
                                                    loc, 
                                                    timeStyle,
                                                    dateStyle,
                                                    flags);
                if (providersInstance != null) {
                    return providersInstance;
                }
            }

            return new SimpleDateFormat(timeStyle, dateStyle, loc);
        } catch (MissingResourceException e) {
            return new SimpleDateFormat("M/d/yy h:mm a");
        }
    }

我们看看重点部分:

首先创建了一个LocaleServiceProviderPool,然后将获取实例的具体逻委托给pool,如果获取不到,则返回一个SimpleDateFormat的实例。

其实这个方法他就是一个很明显的简单工厂方法,只不过是这个抽象类自己同时充当了工厂类的角色。


为什么工厂方法是static? 就以DateFormat为例,首先他是一个抽象类,不能自己实例化。如果工厂方法是不静态方法,那么将无法调用,那么我们假设他不是抽象类,那么我们再试想一下:

首先我们创建了一个DateFormat实例,然后调用他的getTimeInstance()方法,来获取一个他的子类的实例。你会不会觉得很别扭,既然我已经有了如下语句:

DateFormat   format = new DateFormat();  为什么我不直接就写DateFormat format  = new SimpleDateFormat()列?  还要通过format.getTimeInstance()多此一举列?



其实这个简单工厂方法对于开--闭原则的支持有限。如果要扩展,必须修改工厂方法。有一点要申明的是:简单工厂模式并不是单例模式,但它是单例模式的基础。与单例模式有着很大程序的区别。在后面的文件中,我们将会陆续介绍到。那么我们来看一个实际的例子(从书上Copy过来):


农场有很多水果:苹果、葡萄、草莓,假设现在有一名园丁看守农场,我们需要什么,直接问园丁要即可,园丁会帮我们会采摘过来。那么分析一下: 在这个案例中: 水果就是抽象采品,而苹果、葡萄则是具体产品,园丁则是扮演工厂角色。那么则会有如下代码:

public interface Fruit {

	void grow();
	void plant();
	void harvest();
}


package com.pattern.factory.simple;

public class Apple implements Fruit{

	private int treeAge;
	
	
	@Override
	public void grow() {
		log("Apple is growiing....");
		
	}

	@Override
	public void harvest() {
		log("Apple has beean harvested....");
		
	}

	@Override
	public void plant() {
		log("Apple has beean planted....");
		
	}
	
	public static void log(String msg){
		System.out.println(msg);
	}

	public int getTreeAge() {
		return treeAge;
	}

	public void setTreeAge(int treeAge) {
		this.treeAge = treeAge;
	}
	
	
	

}


package com.pattern.factory.simple;

public class Grape implements Fruit {

	
	private boolean seedless;
	
	
	
	public boolean isSeedless() {
		return seedless;
	}

	public void setSeedless(boolean seedless) {
		this.seedless = seedless;
	}

	public static void log(String msg){
		System.out.println(msg);
	}
	
	@Override
	public void grow() {
		log("Grape is growing...");
	}

	@Override
	public void harvest() {
		log("Grape has been harvested.....");

	}

	@Override
	public void plant() {
		log("Grape has been planted........");

	}

}


package com.pattern.factory.simple;

public class Strawberry implements Fruit {

	public static void log(String msg){
		System.out.println(msg);
	}
	
	@Override
	public void grow() {
		// TODO Auto-generated method stub
		log("Strawberry  is growing....");
	}

	@Override
	public void harvest() {
		log("Strawberry has been harvested..........");

	}

	@Override
	public void plant() {
		log("Strawberry has been planted...........");

	}

}


package com.pattern.factory.simple;

public class FruitGardener {

	public static Fruit factory(String which) throws BadFruitException{
		
		if(which.equalsIgnoreCase("apple")){
			return new Apple();
		}
		
		if(which.equalsIgnoreCase("strawberry")){
			return new Strawberry();
		}
		
		if(which.equalsIgnoreCase("grape")){
			return new Grape();
		}
		throw new BadFruitException("bad fruit Exception ");
	}
}

现在我们开始问园丁要苹果:

package com.pattern.factory.simple;

public class TestSimple {

	/**
	 * @param args
	 * @throws BadFruitException 
	 */
	public static void main(String[] args) throws BadFruitException {
		
		Fruit fruit = FruitGardener.factory("apple");
		fruit.grow();
	}

}

从打印结果很明显可以看出,fruit的实例类型是Apple。那么写完这个例子,我们有一点值得反思: 一个农场不可能只有三种水果,那么现在我们种植了更多的水果,如:香蕉、梨、西瓜..... 那么现在我们肯定首先是扩展具体产品,接着是要修改园丁类的工厂方法。 那么显然违背了开---闭原则中的“闭”。而此时,我们的园丁是集万千任务于一身,假设园丁因为某些原因不能工作了,那么怎么找谁要水果去列?  所以这里也体现了简单工厂模式的一个问题:   扩展时,需要修改已有的代码,且工厂类的职能过于集中,若工厂类出现问题,则整个模块将不能正常工作。那么有没有改进办法列? 还是那句话:你永远不会是第一个发现问题的。那么接下来要介绍的工厂方法模式,就针对这个问题,就行了改进了。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值