1.简单工厂模式的不足
在简单工厂模式中,只提供了一个工厂类,该工厂类处于对产品类进行实例化的中心位置,它知道每一个产品对象的创建细节,并决定何时实例化哪一个产品类。简单工厂模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类,加入必要的处理逻辑,这违背了“开闭原则”。在简单工厂模式中,所有的产品都是由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性,而工厂方法模式则可以很好地解决这一问题。
2.工厂方法模式
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
实例:
将上节的案例的工厂进行分割,为每种品牌的电视机提供一个子工厂,海尔工厂专门负责生产海尔电视机,海信工厂专门负责生产海信电视机,如果需要生产TCL电视机或创维电视机,只需要对应增加一个新的TCL工厂或创维工厂即可,原有的工厂无须做任何修改,使得整个系统具有更加的灵活性和可扩展性。
项目结构图如下:


创建抽象产品接口。
package com.simoniu.domain;
public interface TV {
void play();
}
设计两个抽象产品的实现类(海尔电视和海信电视)。
//HaierTV.java
package com.simoniu.domain;
public class HaierTV implements TV {
@Override
public void play() {
System.out.println("海尔电视机播放中....");
}
}
//HisenseTV.java
package com.simoniu.domain;
public class HisenseTV implements TV {
@Override
public void play() {
System.out.println("海信电视机播放中....");
}
}
抽象工厂接口
package com.simoniu.factory;
import com.simoniu.domain.TV;
public interface TVFactory {
TV produceTV();
}
具体产品工厂
//HaierTVFactory.java
package com.simoniu.factory;
import com.simoniu.domain.HaierTV;
import com.simoniu.domain.TV;
public class HaierTVFactory implements TVFactory {
@Override
public TV produceTV() {
System.out.println("海尔电视机工厂生产海尔电视机");
return new HaierTV();
}
}
//HisenseTVFactory.java
package com.simoniu.factory;
import com.simoniu.domain.HaierTV;
import com.simoniu.domain.TV;
public class HisenseTVFactory implements TVFactory {
@Override
public TV produceTV() {
System.out.println("海信电视机工厂生产海信电视机");
return new HisenseTV();
}
}
XML解析工具类
package com.simoniu.utils;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
public class XmlUtils {
//从xml中提取具体类名返回对象
public static Object getBean(){
DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
try {
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
Document document=documentBuilder.parse(XmlUtils.class .getClassLoader().getResourceAsStream("config.xml"));
String className=document.getElementsByTagName("className").item(0).getTextContent();
Class cls=Class.forName(className);
return cls.getDeclaredConstructors()[0].newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
配置文档
<?xml version="1.0"?>
<config>
<!-- <className>com.hsj.factory.HaierTVFactory</className> -->
<className>com.simoniu.factory.HisenseTVFactory</className>
</config>
测试类
package com.simoniu.client;
import com.simoniu.domain.TV;
import com.simoniu.factory.TVFactory;
import com.simoniu.utils.XmlUtils;
public class TestFactoryMethodPatternDemo01 {
public static void main(String[] args) {
TV tv=null;
TVFactory tvFactory=(TVFactory) XmlUtils.getBean();
tv=tvFactory.produceTV();
tv.play();
}
}
运行结果:
海信电视机工厂生产海信电视机
海信电视机播放中....