首先说明一下,这篇文章的理解会有很多的问题,可能你刚刚学习工厂模式容易走进的一个误区,我就走进来了。
看完了这篇文章之后,大家可以看看另一篇文章,这是我的新的认识:http://blog.csdn.net/tayanxunhua/article/details/10297013
我这里通过代码说说简单工厂模式,大家都知道简单工厂模式的定义:根据传入的参数即可返回所需的对象,而不需要知道具体类的类名。
再说一下优缺点:
优点:
1、客户端或者说调用者,不需要知道对象是如何创建的,只管用就可以了,减少了调用者的记忆量(不需要记住类名嘛);
2、通过工厂实现了责任的分割;
3、通过引入配置文件,可以实现在不修改源代码的情况下,更换或添加新的具体产品类(注意:这里我指的是已有产品类的具体类,稍后会解释)。
缺点:
1、工厂类的职责过多,一旦工厂类出现问题,就会影响到整个系统;
2、增加系统中类的个数,进而增加了系统的复杂度;
3、系统扩展比较困难,如果添加新的产品类(如:我添加和已有的产品类(TV类)不同的产品类(Fruit类)),此时就需要更改工厂类中的方法了,因为之前工厂类中只有getTV的静态工厂方法,而没有getFruit的静态工厂方法,所以,只能添加一个这样的静态工厂方法了(这是对前面的解释)。当然了,如果添加TV的具体类(如:TCLTV,然后实现TV类,那么这不违反开闭原则);
4、简单工厂模式使用了静态工厂方法,这就造成了我这个工厂无法形成基于继承的等级结构。举例说明:我现在的工厂类负责生产TV产品,如果我希望通过继承的方法实现,即我有一个总工厂的虚拟类(定义了所有的工厂类),每一个具体的工厂类需要继承这个总的工厂类,而那个总的工厂类中定义了静态的工厂方法,同时它的每个子类同样定义了这个方法,这就会导致这样的问题:定义的时候使用的是父类,实例化的是子类(这样的格式:SuperClass sub = new SubClass(); ),我无法使用子类中的静态方法去创建想要的对象,每次调用的方法都是总工厂类中的静态方法。(因为子类不能重写父类中的静态方法),这回差不多理解了吧;
5、违反了开闭原则,原因可以参考第3条。补充:违反开闭原则的原因不是因为添加已经存在的产品类(如实现TV类的TCLTV类,这里不需要修改工厂类的代码,不过很多资料说简单工厂违反开闭原则是这个原因,我觉得静态工厂方法里面通过反射机制实现对象的创建),而是因为添加新的产品类(如新建一个Fruit接口,然后AppliFruit类实现接口,这样就必须修改工厂类的代码了,其实我认为简单工厂违反开闭原则是这个原因)
好了上代码吧:
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();
}
}