AbstractFactory抽象工厂
抽象工厂为创建一组相关的或互相依赖的类提供一个接口,而无需指定具体的工厂类。我们知道工厂模式的目的是通过一个具体的工厂类来创建一个或多个产品,这样可以让产品的生成逻辑只依赖于工厂类。然而这样同样会造成一个问题,用户的模块将与具体的工厂类相耦合,一旦需要变更产品的种类,那么极为困难。因此出现了抽象工厂模式,它是一个未实现的抽象工厂类,无论具体的工厂如何换,依旧不会影响用户的使用。
使用场景
- 系统需要从多套组件或组合中选择一种使用时,如应用程序需要为用户提供UI风格的切换功能。
- 系统需要完全独立于组件的创建,选择时。如处于下游的独立系统中,不用改去考虑使用说明样的工具和如何创建,这些都应该由上游的系统选择,因此使用抽象工厂能将这些逻辑与系统解耦。
- 当有多个系列组件,并强调使用同一个系列的组件时。如JDBC中,我们使用了Mysql那么就不能使用Oracle的组件。
实现
这里有一个UI系统,它将提供不同风格的UI组件,列如Mac,Ubuntu,Win。各个风格之间,组件的显示区别明显,因此我们希望给用户提供一个方法,能一次性选择使用的风格,并在之后使用同一风格的组件。
这里假设UI组件有button,window,menu那么我们需要为各个组件都创建它们的抽象接口
interface Button{}
interface Window{}
interface Menu{}
之后我们需要设计一个创建它们的抽象工厂类
interface UICreator{
Buttom createButtom();
Window createWindow();
Menu createMenu();
}
最后我们创建不同风格对应的工厂类,如Win
class WinUICreator extends UICreator{
Buttom createButtom(){
return new WinButton();
}
Window createWindow(){
return new WinWindow();
}
Menu createMenu(){
return new WinMenu();
}
}
在实际编程中,我们只需要使用抽象工厂类和其组件接口来开发即可,无需关心组件的具体实现和控件风格的选择。(话是这样说,然而接口定义好了,但并不是每个实现都有相同的调用效果,若出现不兼容情况,那代码就会像s一样难看)
举例
java.sql.Connection
Connection就是抽象工厂:
java.sql.Connection;
public interface Connection extends Wrapper, AutoCloseable {
Statement createStatement() throws SQLException;
PreparedStatement prepareStatement(String sql) throws SQLException;
}
2个产品等级结构:
java.sql.Statement;
java.sql.PreparedStatement;
public interface Statement extends Wrapper, AutoCloseable {...}
public interface PreparedStatement extends Statement {...}
具体工厂:
com.mysql.jdbc.ConnectionImpl
package com.mysql.jdbc;
public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLConnection {
public java.sql.Statement createStatement() throws SQLException {
return createStatement(DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY);
}
public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException {
return prepareStatement(sql, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY);
}
}
优点
- 用户与具体的工厂实现类之间解耦,易于改变工厂实现
- 有利于产品的一致性
缺点
- 难以支持新的产品类型,因为一旦增加一种产品类型,意味着所有的工厂实现都需要进行修改。在《设计模式:可复用面向对象软件的基础》一书中提到,可以使用一种基于字符串或枚举的方式来获取组件的方式,列如
interface UICreator{
Component creatorComponent(String ComponentName);
}
这种方法我认为是不可取的, 首先返回的组件类型已经损失,需要用户强制转型,这是不安全的,其次通过字符串这种非硬编码的方式来创建组件,一旦打错,无法被编译器捕捉到错误。我认为,可以通过适配器来接触工厂类与抽象工厂类之间的耦合关系,这样能完美解决这个问题。
interface UICreator{
Buttom createButtom();
Window createWindow();
Menu createMenu();
ListView createListView();
}
abstract class UICreatorAdapter{
Buttom createButtom(){
throw new UnsupportedOperationException();
}
Window createWindow(){
throw new UnsupportedOperationException();
}
Menu createMenu(){
throw new UnsupportedOperationException();
}
ListView createListView (){
throw new UnsupportedOperationException();
}
}
class WinUICreator extends UICreator{
Buttom createButtom(){
return new WinButton();
}
Window createWindow(){
return new WinWindow();
}
Menu createMenu(){
return new WinMenu();
}
}
网友评论