抽象工厂模式:用汽车工厂的故事理解系列产品创建

56 阅读9分钟

一、故事解说:豪华汽车工厂如何生产不同品牌

假设你要开一家豪华汽车工厂,专门生产高端车:

  1. 系列化生产

    • 奔驰系列:生产奔驰发动机、奔驰轮胎、奔驰内饰;
    • 宝马系列:生产宝马发动机、宝马轮胎、宝马内饰;
  2. 工厂分工

    • 抽象工厂:定义生产发动机、轮胎、内饰的接口;
    • 具体工厂:奔驰工厂只生产奔驰部件,宝马工厂只生产宝马部件;
  3. 客户需求:客户说 “我要一辆奔驰”,工厂自动匹配生产奔驰的全套部件,无需关心细节。

抽象工厂核心:创建一系列相关或依赖的对象(如发动机 + 轮胎 + 内饰),将对象的创建逻辑封装在具体工厂中,客户端只需指定系列,无需知道具体实现。

二、抽象工厂模式核心结构(汽车工厂案例)

java

// 1. 抽象产品1:发动机
interface Engine {
    void start();
}

// 2. 具体产品1:奔驰发动机
class BenzEngine implements Engine {
    @Override
    public void start() {
        System.out.println("奔驰发动机启动,声音低沉有力");
    }
}

// 3. 具体产品1:宝马发动机
class BmwEngine implements Engine {
    @Override
    public void start() {
        System.out.println("宝马发动机启动,声浪澎湃");
    }
}

// 4. 抽象产品2:轮胎
interface Tire {
    void inflate();
}

// 5. 具体产品2:奔驰轮胎
class BenzTire implements Tire {
    @Override
    public void inflate() {
        System.out.println("奔驰轮胎充气至2.5Bar,舒适静音");
    }
}

// 6. 具体产品2:宝马轮胎
class BmwTire implements Tire {
    @Override
    public void inflate() {
        System.out.println("宝马轮胎充气至2.8Bar,运动性能佳");
    }
}

// 7. 抽象工厂:定义生产系列产品的接口
interface CarFactory {
    Engine createEngine();
    Tire createTire();
}

// 8. 具体工厂:奔驰工厂
class BenzFactory implements CarFactory {
    @Override
    public Engine createEngine() {
        return new BenzEngine();
    }
    
    @Override
    public Tire createTire() {
        return new BenzTire();
    }
}

// 9. 具体工厂:宝马工厂
class BmwFactory implements CarFactory {
    @Override
    public Engine createEngine() {
        return new BmwEngine();
    }
    
    @Override
    public Tire createTire() {
        return new BmwTire();
    }
}

// 10. 客户端:使用工厂生产汽车
public class Client {
    public static void main(String[] args) {
        // 创建奔驰工厂
        CarFactory benzFactory = new BenzFactory();
        Engine benzEngine = benzFactory.createEngine();
        Tire benzTire = benzFactory.createTire();
        
        benzEngine.start(); // 输出:奔驰发动机启动...
        benzTire.inflate(); // 输出:奔驰轮胎充气...
        
        // 创建宝马工厂
        CarFactory bmwFactory = new BmwFactory();
        Engine bmwEngine = bmwFactory.createEngine();
        Tire bmwTire = bmwFactory.createTire();
        
        bmwEngine.start(); // 输出:宝马发动机启动...
        bmwTire.inflate(); // 输出:宝马轮胎充气...
    }
}

三、Android 常用抽象工厂模式案例与实现

案例 1:UI 主题工厂(生产不同主题的控件)

java

// 1. 抽象产品1:按钮
interface Button {
    void setBackgroundColor(int color);
    void setText(String text);
}

// 2. 具体产品1:深色主题按钮
class DarkButton implements Button {
    @Override
    public void setBackgroundColor(int color) {
        System.out.println("深色按钮设置背景色:" + color);
    }
    
    @Override
    public void setText(String text) {
        System.out.println("深色按钮设置文字:" + text);
    }
}

// 3. 具体产品1:浅色主题按钮
class LightButton implements Button {
    @Override
    public void setBackgroundColor(int color) {
        System.out.println("浅色按钮设置背景色:" + color);
    }
    
    @Override
    public void setText(String text) {
        System.out.println("浅色按钮设置文字:" + text);
    }
}

// 4. 抽象产品2:文本框
interface EditText {
    void setHint(String hint);
    void setTextColor(int color);
}

// 5. 具体产品2:深色主题文本框
class DarkEditText implements EditText {
    @Override
    public void setHint(String hint) {
        System.out.println("深色文本框设置提示:" + hint);
    }
    
    @Override
    public void setTextColor(int color) {
        System.out.println("深色文本框设置文字颜色:" + color);
    }
}

// 6. 具体产品2:浅色主题文本框
class LightEditText implements EditText {
    @Override
    public void setHint(String hint) {
        System.out.println("浅色文本框设置提示:" + hint);
    }
    
    @Override
    public void setTextColor(int color) {
        System.out.println("浅色文本框设置文字颜色:" + color);
    }
}

// 7. 抽象工厂:主题工厂
interface ThemeFactory {
    Button createButton();
    EditText createEditText();
}

// 8. 具体工厂:深色主题工厂
class DarkThemeFactory implements ThemeFactory {
    @Override
    public Button createButton() {
        return new DarkButton();
    }
    
    @Override
    public EditText createEditText() {
        return new DarkEditText();
    }
}

// 9. 具体工厂:浅色主题工厂
class LightThemeFactory implements ThemeFactory {
    @Override
    public Button createButton() {
        return new LightButton();
    }
    
    @Override
    public EditText createEditText() {
        return new LightEditText();
    }
}

// 10. 在Activity中使用
public class MainActivity extends AppCompatActivity {
    private ThemeFactory themeFactory;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 根据系统主题选择工厂(简化示例,实际中读取系统主题)
        if (isDarkModeEnabled()) {
            themeFactory = new DarkThemeFactory();
        } else {
            themeFactory = new LightThemeFactory();
        }
        
        // 创建按钮和文本框
        Button button = themeFactory.createButton();
        EditText editText = themeFactory.createEditText();
        
        // 设置控件属性
        button.setBackgroundColor(Color.BLUE);
        button.setText("点击我");
        editText.setHint("请输入内容");
        editText.setTextColor(Color.BLACK);
    }
    
    private boolean isDarkModeEnabled() {
        // 实际中检查系统主题
        return false;
    }
}

优点

  • 主题统一管理:同一主题的控件由同一工厂生产,保证风格一致性;

  • 动态切换主题:运行时切换工厂即可切换整个界面风格;

  • 扩展性好:新增主题(如红色主题、绿色主题)只需添加新工厂和产品,不修改现有代码。

缺点

  • 类数量爆炸:每个主题需要按钮、文本框等多个产品类,主题多了类数翻倍;
  • 耦合度较高:产品之间存在隐含依赖(如深色按钮必须配深色文本框),修改一处可能影响整体。

案例 2:数据库工厂(生产不同类型的数据库连接)

java

// 1. 抽象产品1:数据库连接
interface DbConnection {
    void connect();
    void close();
}

// 2. 具体产品1:SQLite连接
class SqliteConnection implements DbConnection {
    @Override
    public void connect() {
        System.out.println("连接SQLite数据库");
    }
    
    @Override
    public void close() {
        System.out.println("关闭SQLite连接");
    }
}

// 3. 具体产品1:MySQL连接(Android中需通过JDBC驱动)
class MysqlConnection implements DbConnection {
    @Override
    public void connect() {
        System.out.println("连接MySQL数据库(需JDBC驱动)");
    }
    
    @Override
    public void close() {
        System.out.println("关闭MySQL连接");
    }
}

// 4. 抽象产品2:数据库操作
interface DbOperation {
    void query(String sql);
    void insert(String sql);
}

// 5. 具体产品2:SQLite操作
class SqliteOperation implements DbOperation {
    @Override
    public void query(String sql) {
        System.out.println("SQLite执行查询:" + sql);
    }
    
    @Override
    public void insert(String sql) {
        System.out.println("SQLite执行插入:" + sql);
    }
}

// 6. 具体产品2:MySQL操作
class MysqlOperation implements DbOperation {
    @Override
    public void query(String sql) {
        System.out.println("MySQL执行查询:" + sql);
    }
    
    @Override
    public void insert(String sql) {
        System.out.println("MySQL执行插入:" + sql);
    }
}

// 7. 抽象工厂:数据库工厂
interface DbFactory {
    DbConnection createConnection();
    DbOperation createOperation();
}

// 8. 具体工厂:SQLite工厂
class SqliteFactory implements DbFactory {
    @Override
    public DbConnection createConnection() {
        return new SqliteConnection();
    }
    
    @Override
    public DbOperation createOperation() {
        return new SqliteOperation();
    }
}

// 9. 具体工厂:MySQL工厂
class MysqlFactory implements DbFactory {
    @Override
    public DbConnection createConnection() {
        return new MysqlConnection();
    }
    
    @Override
    public DbOperation createOperation() {
        return new MysqlOperation();
    }
}

// 10. 在Activity中使用
public class DbActivity extends AppCompatActivity {
    private DbFactory dbFactory;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 根据配置选择数据库(简化示例)
        if (useLocalDb()) {
            dbFactory = new SqliteFactory();
        } else {
            dbFactory = new MysqlFactory();
        }
        
        // 获取连接和操作对象
        DbConnection connection = dbFactory.createConnection();
        DbOperation operation = dbFactory.createOperation();
        
        // 执行数据库操作
        connection.connect();
        operation.query("SELECT * FROM users");
        operation.insert("INSERT INTO logs VALUES(...)");
        connection.close();
    }
    
    private boolean useLocalDb() {
        // 实际中读取配置
        return true;
    }
}

优点

  • 数据库解耦:客户端不依赖具体数据库实现,便于切换(如本地 SQLite 或远程 MySQL);

  • 统一操作接口:无论哪种数据库,操作方式一致,降低学习成本;

  • 测试方便:测试时可使用轻量级 SQLite 工厂,生产环境切换到 MySQL 工厂。

缺点

  • 实现复杂度高:需要为每种数据库实现全套产品,工作量大;
  • 性能考虑:抽象工厂的多层调用可能带来微小性能开销,需权衡。

案例 3:网络请求工厂(生产不同类型的请求)

java

// 1. 抽象产品1:GET请求
interface GetRequest {
    void send(String url);
}

// 2. 具体产品1:OkHttp GET请求
class OkHttpGetRequest implements GetRequest {
    @Override
    public void send(String url) {
        System.out.println("OkHttp发送GET请求:" + url);
    }
}

// 3. 具体产品1:Retrofit GET请求
class RetrofitGetRequest implements GetRequest {
    @Override
    public void send(String url) {
        System.out.println("Retrofit发送GET请求:" + url);
    }
}

// 4. 抽象产品2:POST请求
interface PostRequest {
    void send(String url, String data);
}

// 5. 具体产品2:OkHttp POST请求
class OkHttpPostRequest implements PostRequest {
    @Override
    public void send(String url, String data) {
        System.out.println("OkHttp发送POST请求到" + url + ",数据:" + data);
    }
}

// 6. 具体产品2:Retrofit POST请求
class RetrofitPostRequest implements PostRequest {
    @Override
    public void send(String url, String data) {
        System.out.println("Retrofit发送POST请求到" + url + ",数据:" + data);
    }
}

// 7. 抽象工厂:网络请求工厂
interface NetworkFactory {
    GetRequest createGetRequest();
    PostRequest createPostRequest();
}

// 8. 具体工厂:OkHttp工厂
class OkHttpFactory implements NetworkFactory {
    @Override
    public GetRequest createGetRequest() {
        return new OkHttpGetRequest();
    }
    
    @Override
    public PostRequest createPostRequest() {
        return new OkHttpPostRequest();
    }
}

// 9. 具体工厂:Retrofit工厂
class RetrofitFactory implements NetworkFactory {
    @Override
    public GetRequest createGetRequest() {
        return new RetrofitGetRequest();
    }
    
    @Override
    public PostRequest createPostRequest() {
        return new RetrofitPostRequest();
    }
}

// 10. 在Activity中使用
public class NetworkActivity extends AppCompatActivity {
    private NetworkFactory networkFactory;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 根据配置选择网络框架(简化示例)
        if (useOkHttp()) {
            networkFactory = new OkHttpFactory();
        } else {
            networkFactory = new RetrofitFactory();
        }
        
        // 创建请求对象
        GetRequest getRequest = networkFactory.createGetRequest();
        PostRequest postRequest = networkFactory.createPostRequest();
        
        // 发送请求
        getRequest.send("https://api.example.com/data");
        postRequest.send("https://api.example.com/upload", "{"key":"value"}");
    }
    
    private boolean useOkHttp() {
        // 实际中读取配置
        return true;
    }
}

优点

  • 框架解耦:客户端不依赖具体网络框架(OkHttp/Retrofit),便于切换或升级;

  • 统一请求接口:无论哪种框架,GET/POST 请求接口一致,代码更统一;

  • 扩展性好:新增网络框架(如 Volley)只需添加新工厂和产品,不影响现有代码。

缺点

  • 维护成本高:需要为每个框架维护一套请求产品,框架升级时可能需要同步修改;
  • 过度设计风险:对于小型项目,抽象工厂可能增加复杂度,不如直接使用单一框架。

四、抽象工厂模式的适用场景与总结

适用场景

  1. 系列产品创建:需要创建一系列相关或依赖的对象(如主题控件、数据库连接、网络请求);
  2. 多产品线支持:系统需要支持多个产品系列(如深色 / 浅色主题、SQLite/MySQL 数据库);
  3. 解耦具体实现:客户端不希望依赖具体产品的创建逻辑,只关心抽象接口;
  4. 统一产品风格:确保同一工厂生产的产品风格一致(如同一主题的所有控件)。

核心优点

  • 封装系列创建:将系列产品的创建逻辑封装在工厂中,客户端无需关心细节;
  • 解耦产品与客户端:客户端只依赖抽象接口,不依赖具体实现,提高可维护性;
  • 保证产品一致性:同一工厂生产的产品相互兼容,避免风格或功能冲突;
  • 符合开闭原则:新增产品系列只需添加新工厂和产品,不修改现有代码。

核心缺点

  • 类数量爆炸:每个产品系列需要多个产品类和工厂类,导致类数快速增加;
  • 扩展新产品困难:若要新增一种产品(如主题中添加 TextView),需修改所有工厂接口和实现;
  • 性能开销:多层抽象和接口可能带来微小的性能开销,不过在 Android 中通常可忽略。

Android 中的最佳实践

  • 主题切换场景:使用抽象工厂管理不同主题的控件,保证界面一致性;

  • 多数据源支持:如同时支持本地数据库和远程 API,用抽象工厂封装数据源创建;

  • 框架适配层:当项目需要支持多种框架(如图片加载库)时,用抽象工厂隔离框架差异;

  • 结合其他模式:与单例模式结合(工厂使用单例),与 builder 模式结合(复杂产品的构建)。

抽象工厂模式是大型项目中管理系列化对象创建的有力工具,虽然实现成本较高,但在需要支持多产品线或动态切换产品系列的场景中,能带来显著的架构优势。