设计模式 - 简单工厂模式

我这里通过代码说说简单工厂模式,大家都知道简单工厂模式的定义:根据传入的参数即可返回所需的对象,而不需要知道具体类的类名。

再说一下优缺点:


优点:

1、客户端或者说调用者,不需要知道对象是如何创建的,只管用就可以了,减少了调用者的记忆量(不需要记住类名嘛);


2、通过工厂实现了责任的分割;


3、通过引入配置文件,可以实现在不修改源代码的情况下,更换或添加新的具体产品类。


缺点:

1、工厂类的职责过多,一旦工厂类出现问题,就会影响到整个系统;


2、增加系统中类的个数,进而增加了系统的复杂度;


3、系统扩展比较困难,如果添加新的产品(指的是同一种产品的具体类)就不得不修改工厂类中的静态工厂方法中的逻辑;


4、简单工厂模式使用了静态工厂方法,这就造成了我这个工厂无法形成基于继承的等级结构。举例说明:我现在的工厂类负责生产TV产品,如果我希望通过继承的方法实现,即我有一个总工厂的虚拟类(定义了所有的工厂类),每一个具体的工厂类需要继承这个总的工厂类,而那个总的工厂类中定义了静态的工厂方法,同时它的每个子类同样定义了这个方法,这就会导致这样的问题:定义的时候使用的是父类,实例化的是子类(这样的格式:SuperClass sub  =  new SubClass(); ),我无法使用子类中的静态方法去创建想要的对象,每次调用的方法都是总工厂类中的静态方法。(因为子类不能重写父类中的静态方法),这回差不多理解了吧;


5、违反了开闭原则,原因可以参考第3条。


好了上代码吧:

package com.tyxh.pattern.sample;

public interface TV {

	public void play();
}

package com.tyxh.pattern.sample;

public class HaierTV implements TV {

	@Override
	public void play() {
		System.out.println("Haier TV");
	}

}

package com.tyxh.pattern.sample;

public class HisenseTV implements TV {

	@Override
	public void play() {
		System.out.println("Hisense TV");
	}

}

package com.tyxh.pattern.sample;

public class TVFactory {
	
	public static TV getTV(String name) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
//		TV tv = (TV) Class.forName("com.tyxh.pattern.sample." + name).newInstance();
//		return tv;
		
		if (name.equals("Haier")) {
			return new HaierTV();
		} else if (name.equals("Hisense")) {
			return new HisenseTV();
		} else {
			return null;
		}
	}
	
}

package com.tyxh.pattern.sample;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLUtil {
	public static String getBrandName() {
		try {
			//创建文档对象
			DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = dFactory.newDocumentBuilder();
			Document doc = builder.parse(new File("src/com/tyxh/pattern/sample/config.xml"));
			
			//获取节点
			NodeList nl = doc.getElementsByTagName("brandName");
			Node classNode = nl.item(0).getFirstChild();
			String brandName = classNode.getNodeValue().trim();
			return brandName;
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		}
		
	}
}

<!--config.xml-->
<?xml version="1.0"?>
<config>
	<brandName>TyxhTV</brandName>
</config>

package com.tyxh.pattern.sample;

public class Client {

	public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		String brandName = XMLUtil.getBrandName();
		TV tv = TVFactory.getTV(brandName);
		tv.play();
	}
}

 

注意:上面TVFactory工厂类我在注释里通过反射机制创建了对象,想利用这种方式来替换if...else逻辑,不过有些不妥,所以我又将其注释掉了,以前我一直存在个疑问:

就是上面缺点中的第三条:3、系统扩展比较困难,如果添加新的产品(指的是同一种产品的具体类)就不得不修改工厂类中的静态工厂方法中的逻辑;

“添加新产品”,这个产品是指的什么?指的是TV产品的具体类(例如,再添加一个TCLTV)?还是指的是非TV产品(例如,添加个苹果具体实现类)?

如果是第一种情况,那么我们可以新创建一个TCLTV实现TV接口,然后在工厂类中的静态工厂方法里面修改if...else逻辑,当然了很多人会想,包括我,我可以用反射机制实现嘛,这样不就是可以不修改工厂类了嘛。恩,确实是的,不过,使用反射机制还是有很多限制的,反射生成的对象只能适用一些最简单的情况,如果对象的创建过程比较复杂,例如要调用有参构造函数,或者创建之前要配置环境等,反射还如何实现?这就需要将这些代码封装到工厂中。反射生成对象只能适用一些最简单的情况,如果对象的创建过程比较复杂,例如要调用有参构造函数、创建之前要配置环境等等,需要将这些代码封装到工厂中。需要仔细理解工厂的作用,而不是简单的创建一个对象。

如果是第二种情况,那么我们就没有必要将苹果具体实现类放到TVFactory工厂中去生产了,完全不是一个东西啊。再新建一个FruitFactory工厂吧,在这个工厂类中的静态工厂方法实现苹果对象的创建。

我以前的理解是这样的:http://blog.csdn.net/tayanxunhua/article/details/10313325

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值