一、为什么需要工厂模式?
想象一下你正在开发一个外卖APP,里面需要创建各种不同类型的餐厅对象:中餐馆、西餐厅、日料店等等。如果每次都要用new关键字直接创建,代码会变成这样:
// 技术栈:Dart
ChineseRestaurant restaurant1 = new ChineseRestaurant();
WesternRestaurant restaurant2 = new WesternRestaurant();
JapaneseRestaurant restaurant3 = new JapaneseRestaurant();
这样写有三个明显问题:
- 创建逻辑散落在代码各处,难以统一管理
- 如果要修改创建方式,需要改动所有创建代码
- 客户端代码需要知道所有具体类,耦合度太高
工厂模式就像个"对象生产车间",把对象的创建过程封装起来,让调用方不需要关心具体实现细节。这特别适合以下场景:
- 对象创建过程比较复杂
- 需要根据不同条件创建不同对象
- 希望隐藏对象的具体实现
二、简单工厂模式实战
我们先来看最简单的实现方式:
// 技术栈:Dart
// 餐厅抽象类
abstract class Restaurant {
void serveFood();
}
// 具体餐厅类
class ChineseRestaurant implements Restaurant {
@override
void serveFood() {
print('提供宫保鸡丁和米饭');
}
}
class WesternRestaurant implements Restaurant {
@override
void serveFood() {
print('提供牛排和红酒');
}
}
// 简单工厂类
class RestaurantFactory {
static Restaurant createRestaurant(String type) {
switch (type) {
case 'chinese':
return ChineseRestaurant();
case 'western':
return WesternRestaurant();
default:
throw Exception('不支持的餐厅类型');
}
}
}
// 使用示例
void main() {
// 客户端只需要知道工厂类和抽象类型
Restaurant restaurant = RestaurantFactory.createRestaurant('chinese');
restaurant.serveFood(); // 输出:提供宫保鸡丁和米饭
}
这个例子展示了工厂模式的核心思想:
- 定义统一的接口(Restaurant)
- 把创建逻辑集中到工厂类中
- 客户端通过工厂获取实例,而不直接new具体类
三、工厂方法模式进阶
当餐厅类型越来越多时,简单工厂的switch-case会变得臃肿。这时可以用工厂方法模式:
// 技术栈:Dart
// 抽象工厂
abstract class RestaurantFactory {
Restaurant createRestaurant();
// 可以添加一些默认实现
void prepareIngredients() {
print('准备基础食材...');
}
}
// 具体工厂
class ChineseRestaurantFactory implements RestaurantFactory {
@override
Restaurant createRestaurant() {
return ChineseRestaurant();
}
@override
void prepareIngredients() {
super.prepareIngredients();
print('特别准备酱油和生姜');
}
}
// 使用示例
void main() {
RestaurantFactory factory = ChineseRestaurantFactory();
factory.prepareIngredients();
Restaurant restaurant = factory.createRestaurant();
restaurant.serveFood();
}
工厂方法模式的特点:
- 每个具体类对应一个具体工厂
- 可以重写工厂的准备工作
- 符合开闭原则,新增类型时不需要修改已有代码
四、抽象工厂模式实战
当需要创建一系列相关对象时,抽象工厂更有优势。比如我们的餐厅需要配套的餐具:
// 技术栈:Dart
// 餐具抽象
abstract class Tableware {
String getMaterial();
}
// 餐厅抽象工厂
abstract class RestaurantKit {
Restaurant createRestaurant();
Tableware createTableware();
}
// 中式实现
class ChineseRestaurantKit implements RestaurantKit {
@override
Restaurant createRestaurant() => ChineseRestaurant();
@override
Tableware createTableware() => ChineseTableware();
}
class ChineseTableware implements Tableware {
@override
String getMaterial() => '瓷器';
}
// 使用示例
void main() {
RestaurantKit kit = ChineseRestaurantKit();
Restaurant restaurant = kit.createRestaurant();
Tableware tableware = kit.createTableware();
print('使用${tableware.getMaterial()}餐具'); // 输出:使用瓷器餐具
restaurant.serveFood();
}
抽象工厂适合:
- 需要确保创建的对象是兼容的
- 系统需要多个产品族
- 产品之间有明确的关联关系
五、工厂模式的应用场景
工厂模式特别适合以下开发场景:
- 跨平台UI开发 比如Flutter中,根据不同平台创建不同的按钮样式:
// 技术栈:Dart
Button createButton(Platform platform) {
if (platform == Platform.android) {
return MaterialButton();
} else if (platform == Platform.ios) {
return CupertinoButton();
}
}
- 数据库访问 创建不同类型的数据库连接:
// 技术栈:Dart
DatabaseConnection createConnection(DatabaseType type) {
switch (type) {
case DatabaseType.mysql:
return MySqlConnection();
case DatabaseType.postgres:
return PostgresConnection();
}
}
- 插件系统 动态加载和创建插件实例:
// 技术栈:Dart
Plugin createPlugin(String pluginName) {
// 通过反射动态创建插件实例
}
六、技术优缺点分析
优点:
- 解耦:客户端和具体实现解耦
- 可扩展:新增类型很方便
- 统一管理:创建逻辑集中处理
- 可测试:便于mock对象
缺点:
- 增加复杂度:需要多写一些类
- 需要设计:前期需要合理规划层次
- 过度设计:简单场景可能不需要
注意事项:
- 不要滥用,简单对象直接new就行
- 考虑使用依赖注入框架替代手动实现
- 工厂类命名要清晰,比如XXXFactory
- 考虑线程安全问题(Dart中通常不需要)
七、总结
工厂模式是解决对象创建难题的利器,特别是当你的代码中频繁出现new关键字时,就该考虑使用工厂模式了。在Dart中实现工厂模式有几点建议:
- 优先使用工厂构造函数 Dart支持特殊的工厂构造函数语法:
class Restaurant {
factory Restaurant.fromType(String type) {
switch (type) {
case 'chinese': return ChineseRestaurant();
default: throw Exception('不支持的餐厅类型');
}
}
}
- 考虑使用顶层函数 Dart中函数是一等公民,简单的工厂可以直接用函数:
Restaurant createRestaurant(String type) {
// 工厂逻辑
}
- 结合Dart的其他特性 比如可以使用扩展方法增强已有类的工厂能力:
extension RestaurantExtension on String {
Restaurant toRestaurant() {
switch (this) {
case 'chinese': return ChineseRestaurant();
default: throw Exception('不支持的餐厅类型');
}
}
}
// 使用
var restaurant = 'chinese'.toRestaurant();
记住,设计模式不是银弹,关键是理解其思想。在实际开发中,你可以根据项目规模灵活调整实现方式,找到最适合的方案。
工厂模式就像是一个好厨师,它知道每种食材应该怎么处理,而你只需要告诉它"我要一份中餐",它就会为你准备好一切。学会合理使用工厂模式,能让你的代码更加优雅、更易维护。
评论