<span style="font-size:18px;background-color: rgb(255, 255, 255);">工厂方法模式提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方法,创建具体的产品对象。工厂方法模式结构如图</span>
1. 主要优点
工厂方法模式的主要优点如下:
(1) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
(2) 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
(3) 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
2. 主要缺点
工厂方法模式的主要缺点如下:
(1) 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
3. 适用场景
在以下情况下可以考虑使用工厂方法模式:
(1) 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。
(2) 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
练习
使用工厂方法模式设计一个程序来读取各种不同类型的图片格式,针对每一种图片格式都设计一个图片读取器,如GIF图片读取器用于读取GIF格式的图片、JPG图片读取器用于读取JPG格式的图片。需充分考虑系统的灵活性和可扩展性。
具体的java实习代码:
package com.zy;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.File;
//抽象产品
interface picture{
void readPicture();
}
//具体产品
class gifPicture implements picture{
public void readPicture(){
System.out.println("读取GIF格式的图片");
}
}
//具体产品
class jpgPicture implements picture{
public void readPicture(){
System.out.println("读取JPG格式的图片");
}
}
//抽象工厂
interface pictFactory{
picture createPict();
}
//具体工厂
class GIFFactory implements pictFactory{
public picture createPict(){
gifPicture gif=new gifPicture();
return gif;
}
}
//具体工厂
class JPGFactory implements pictFactory{
public picture createPict(){
jpgPicture jpg=new jpgPicture();
return jpg;
}
}
//读取配置文件中具体工厂名称
class XMLUtil{
public static Object getBean(){
try{
DocumentBuilderFactory DBF=DocumentBuilderFactory.newInstance();
DocumentBuilder DB=DBF.newDocumentBuilder();
Document doc=DB.parse(new File("c:\\config.xml"));
NodeList n1=doc.getElementsByTagName("className");
Node node=n1.item(0).getFirstChild();
String className=node.getNodeValue().trim();
Class<?> clazz=Class.forName(className);
Object obj=clazz.newInstance();
return obj;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
public class FactoryMethod {
public static void main(String[] args) {
pictFactory pf;
picture pic;
pf=(pictFactory)XMLUtil.getBean();
pic=pf.createPict();
pic.readPicture();
}
}