文章目录
- 一、抽象工厂模式定义
- 二、抽象工厂模式的结构和说明
- 三、应用抽象工厂模式来解决问题的思路
- 四、抽象工厂模式示例
- 五、抽象工厂模式的优缺点
- 六、用反射机制+简单工厂模式改进代码
- 七、抽象工厂模式的应用场景
一、抽象工厂模式定义
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
二、抽象工厂模式的结构和说明
- AbstractFactory 抽象工厂,定义创建系列产品对象的操作接口。
- ConcreteFactory 具体的工厂,实现抽象工厂定义的方法,具体实现系列产品对象的创建。
- AbstractProduct 产品对象接口。
- Product 实现产品对象接口的实现类。
三、应用抽象工厂模式来解决问题的思路
创建一系列的产品对象,而且这一系列对象是构成新的对象所需要的组成部分,也就是这一系列被创建的对象相互之间是有关联的。
解决这个问题的一个解决方案就是抽象工厂模式。在这个模式里,会定义一个抽象工厂,在里边虚拟的创建客户端需要的这一系列对象,所谓虚拟的就是定义创建这些对象的抽象方法,并不去真正的实现,然后由具体的抽象工厂的子类来提供这一系列对象的创建。这样一来,可以为同一个抽象工厂提供很多不同的实现,那么创建的这一系列对象也就不同了。
四、抽象工厂模式示例
假设鼠标和键盘是我们需要的产品,生产鼠标和键盘的戴尔和联想是我们的工厂。
1、创建鼠标接口和具体的鼠标实现类
Mouse.java
/**
* 鼠标接口
*/
public interface Mouse {
/**
* 点击鼠标
*/
public void click();
}
DellMouse.java
/**
* 戴尔鼠标
*/
public class DellMouse implements Mouse {
@Override
public void click() {
System.out.println("使用戴尔鼠标进行点击...");
}
}
LenovoMouse.java
/**
* 联想鼠标
*/
public class LenovoMouse implements Mouse {
@Override
public void click() {
System.out.println("使用联想鼠标进行点击...");
}
}
2、创建键盘接口和具体的键盘实现类
Keyboard.java
/**
* 键盘接口
*/
public interface Keyboard {
/**
* 使用键盘打字
*/
public void type();
}
DellKeyboard.java
/**
* 戴尔键盘
*/
public class DellKeyboard implements Keyboard {
@Override
public void type() {
System.out.println("使用戴尔键盘打字...");
}
}
LenovoKeyboard.java
/**
* 联想键盘
*/
public class LenovoKeyboard implements Keyboard {
@Override
public void type() {
System.out.println("使用联想键盘打字...");
}
}
3、创建获取鼠标对象和键盘对象的抽象工厂
AbstractFactory.java
/**
* 抽象工厂的接口,声明创建抽象产品对象的操作
*/
public interface AbstractFactory {
/**
* 创建鼠标对象
* @return
*/
public Mouse createMouse();
/**
* 创建键盘对象
* @return
*/
public Keyboard createKeyboard();
}
4、创建实现了抽象工厂的子工厂:戴尔工厂和联想工厂
DellFactory.java
/**
* 戴尔工厂,生产戴尔鼠标和键盘
*/
public class DellFactory implements AbstractFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
@Override
public Keyboard createKeyboard() {
return new DellKeyboard();
}
}
LenovoFactory.java
/**
* 联想工厂,生产联想鼠标和键盘
*/
public class LenovoFactory implements AbstractFactory {
@Override
public Mouse createMouse() {
return new LenovoMouse();
}
@Override
public Keyboard createKeyboard() {
return new LenovoKeyboard();
}
}
5、在客户端用的时候,就可以这样用:
public class Client {
public static void main(String[] args) {
// 使用戴尔工厂
AbstractFactory af = new DellFactory();
Mouse m = af.createMouse();
Keyboard kb = af.createKeyboard();
m.click(); // 使用戴尔鼠标进行点击...
kb.type(); // 使用戴尔键盘打字...
// 更换为联想工厂
af = new LenovoFactory();
m = af.createMouse();
kb = af.createKeyboard();
m.click(); // 使用联想鼠标进行点击...
kb.type(); // 使用联想键盘打字...
}
}
五、抽象工厂模式的优缺点
优点:
- 分离接口和实现。客户端面向产品的接口编程,从具体的产品实现中解耦。
- 可以很方便的生产或切换产品系列。
缺点:
- 不太容易扩展新产品。假如我们要给产品系列添加新的产品耳麦,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。
六、用反射机制+简单工厂模式改进代码
我们将AbstractFactory、DellFactory以及LenovoFactory三个工厂类抛弃掉。取而代之的是一个简单工厂类SimpleFactory。
1、创建简单工厂
SimpleFactory.java
/**
* 简单工厂,生产鼠标和键盘
*/
public class SimpleFactory {
// 包名(此处getProperty方法为从配置文件中获取数据)
private static String packName = getProperty("packName");
// 具体需要的产品系列类型
//(此处getProperty方法为从配置文件中获取数据)
private static String type = getProperty("type");
/**
* 创建需要的鼠标对象
* @return
* @throws Exception
*/
public static Mouse createMouse() throws Exception {
String className = packName + "." + type + "Mouse";
return (Mouse)Class.forName(className).newInstance();
}
/**
* 创建需要的键盘对象
* @return
* @throws Exception
*/
public static Keyboard createKeyboard() throws Exception{
String className = packName + "." + type + "Keyboard";
return (Keyboard)Class.forName(className).newInstance();
}
}
2、配置文件中
packName=com.abstractfactory.example type=Dell
3、在客户端用的时候,就可以这样用:
public class Client {
public static void main(String[] args) throws Exception {
Mouse m = SimpleFactory.createMouse();
Keyboard kb = SimpleFactory.createKeyboard();
m.click(); // 使用戴尔鼠标进行点击...
kb.type(); // 使用戴尔键盘打字...
}
}
这样,如果我们需要更换产品系列,就可以不用修改和编译代码,直接修改配置文件就可以了。
七、抽象工厂模式的应用场景
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。
- 在很多软件系统中需要更换界面主题或者一键换肤。
- DAO层支持多种类型的数据库,动态切换时。
- 不同操作系统代码差异化,可以切换不同操作系统时。