我这里通过代码说说简单工厂模式,大家都知道简单工厂模式的定义:根据传入的参数即可返回所需的对象,而不需要知道具体类的类名。
再说一下优缺点:
优点:
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