设计模式学习(六)——《大话设计模式》
简单工厂模式(Simple Factory Pattern),也称为静态工厂方法模式,它属于类创建型模式。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
工作原理
简单工厂模式的核心思想是有一个中心化的类(简单工厂类),这个类的职责非常明确:负责创建其他类的实例。
客户端只需要传递给工厂类一个参数,就可以获取到必须的实例对象,而无需关心其创建细节。
结构组成
简单工厂模式主要包含以下三个角色:
工厂角色(Factory):这是实现创建所有实例的内部逻辑的类。通常由一个具体类实现。
抽象产品角色(Product):这是一个抽象类或接口,新创建的对象通常都实现或继承自这个类或接口。
具体产品角色(Concrete Product):这是工厂类创建的目标类,继承自抽象产品角色或实现了产品角色定义的接口。
优缺点
优点:
工厂类含有必要的逻辑判断,可以决定在什么时候创建哪一个产品类的实例。使用者可以免除直接创建产品对象的责任,而仅仅"消费"产品。
客户端无需知道所创建具体产品的类名,只需知道参数即可。
缺点:
- 工厂类集中了所有产品的创建逻辑,一旦这个工厂不能工作,整个系统都会受到影响。
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品种类较多时,会使得系统非常复杂。
- 简单工厂模式由于使用了静态方法,造成工厂角色无法形成基于继承的等级结构。
应用场景
简单工厂模式适用于以下场景:
工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端不需要知道具体产品类的类名,只需要知道参数即可。
示例代码
以Python为例,展示一个简单工厂模式的实现:
# 定义一个抽象产品类
class Product:# 定义一个使用产品的抽象方法,具体实现留给子类def use(self):pass# 定义具体产品类A,继承自Product
class ConcreteProductA(Product):# 实现父类的use()方法def use(self):print("Inside ConcreteProductA's use() method.")# 定义具体产品类B,继承自Product
class ConcreteProductB(Product):# 实现父类的use()方法def use(self):print("Inside ConcreteProductB's use() method.")# 定义简单工厂类
class SimpleFactory:# 定义一个静态方法,用于创建产品实例@staticmethoddef create_product(type):# 根据传入的类型参数决定创建哪种具体产品实例if type == 'A':return ConcreteProductA()elif type == 'B':return ConcreteProductB()# 如果传入的类型既不是'A'也不是'B',则返回Nonereturn None# 客户端代码
# 使用简单工厂类创建一个类型为'A'的产品实例
product = SimpleFactory.create_product('A')
# 调用产品实例的use()方法
product.use()
首先定义了一个Product抽象类,然后定义了两个具体的产品类ConcreteProductA和ConcreteProductB,它们都继承自Product类并实现了use()方法。SimpleFactory类通过其静态方法create_product根据传入的类型参数来决定创建哪种具体产品实例。客户端代码仅需通过简单工厂类即可获取到所需的产品实例,无需直接跟具体的产品类发生耦合,从而简化了客户端的使用过程。
在这个例子中,SimpleFactory::create_product方法根据传入的字符串参数决定创建哪种类型的产品实例。这个方法返回一个实现了Product特征的对象的Box(一个智能指针),这样我们就可以在运行时多态地调用operation方法。
定义一个产品特征(trait),以及两种具体的产品结构体
// 定义产品特征
trait Product {fn operation(&self) -> String;
}// 第一个具体产品
struct ConcreteProductA;impl Product for ConcreteProductA {fn operation(&self) -> String {String::from("结果来自于产品A")}
}// 第二个具体产品
struct ConcreteProductB;impl Product for ConcreteProductB {fn operation(&self) -> String {String::from("结果来自于产品B")}
}
定义一个简单工厂结构体,它有一个静态方法用于根据条件创建不同的产品实例:
// 简单工厂
struct SimpleFactory;impl SimpleFactory {// 静态方法,根据类型创建不同的产品实例fn create_product(product_type: &str) -> Box<dyn Product> {match product_type {"A" => Box::new(ConcreteProductA),"B" => Box::new(ConcreteProductB),_ => panic!("不支持的产品类型"),}}
}
使用简单工厂来创建和使用产品:
fn main() {let product_a = SimpleFactory::create_product("A");println!("{}", product_a.operation());let product_b = SimpleFactory::create_product("B");println!("{}", product_b.operation());
}
UML类图
工厂(Factory) - 负责创建产品对象的类。它通常包含一个或多个方法,这些方法用于根据输入参数决定创建哪种具体产品的实例。
抽象产品(Abstract Product) - 由一个接口或抽象类表示,定义了产品对象的公共接口。
具体产品(Concrete Product) - 实现或继承自抽象产品,表示具体的产品对象。
+-------------------+| <<interface>> || Abstract || Product |+-------------------+^ ^| |
+---------------+ +----------------+
| |
| |
| |
+-------------------+ +-------------------+
| Concrete | | Concrete |
| Product A | | Product B |
+-------------------+ +-------------------+^ ^| || |+-----------+------------+||+-------------------+| Factory |+-------------------+| +createProduct() |+-------------------+
- Abstract Product 表示产品的公共接口,它定义了所有具体产品应该实现的操作。
- Concrete Product A 和 Concrete Product B 是实现了抽象产品接口的具体类,代表了不同类型的产品。
- Factory 是一个包含 createProduct 方法的类。这个方法根据输入参数决定并返回具体产品的实例。在 Rust 的实现中,这个角色通常通过一个结构体(如 SimpleFactory)和一个关联函数(如 create_product)来实现。
具体应用和使用场景
日志记录:
在需要实现日志记录功能时,可以使用简单工厂模式来创建不同类型的日志记录器(如文件日志记录器、数据库日志记录器等)。这样,应用程序可以根据配置或运行时条件选择合适的日志记录方式,而无需修改现有代码。
#有一个应用,需要根据不同的环境(开发环境、生产环境)来选择不同的日志记录方式(控制台日志、文件日志)。
class Logger:def log(self, message):passclass ConsoleLogger(Logger):def log(self, message):print(f"Console log: {message}")class FileLogger(Logger):def log(self, message):with open("app.log", "a") as file:file.write(f"File log: {message}\n")class LoggerFactory:@staticmethoddef get_logger(environment):if environment == 'development':return ConsoleLogger()elif environment == 'production':return FileLogger()else:raise ValueError("Invalid environment")# 客户端代码
logger = LoggerFactory.get_logger('development')
logger.log("This is a log message.")
数据库访问:
在访问不同类型的数据库时(如MySQL、SQLite、Oracle等),可以通过简单工厂模式提供一个统一的接口来创建不同类型的数据库连接对象。这样,当需要更换数据库或同时支持多种数据库时,只需修改工厂类中的逻辑即可。
#需要连接不同类型的数据库时,可以定义一个简单工厂来创建不同类型的数据库连接。
class DatabaseConnection:def connect(self):passclass MySQLConnection(DatabaseConnection):def connect(self):print("Connecting to MySQL database...")class SQLiteConnection(DatabaseConnection):def connect(self):print("Connecting to SQLite database...")class DatabaseConnectionFactory:@staticmethoddef get_database_connection(database_type):if database_type == 'MySQL':return MySQLConnection()elif database_type == 'SQLite':return SQLiteConnection()else:raise ValueError("Invalid database type")# 客户端代码
db_connection = DatabaseConnectionFactory.get_database_connection('SQLite')
db_connection.connect()
GUI组件创建:
在开发图形用户界面(GUI)应用程序时,简单工厂模式可以用来创建不同类型的GUI组件,如按钮、文本框、复选框等。根据不同的需求或风格,可以轻松切换组件的具体实现。
#GUI应用程序中,根据不同的需求创建不同类型的按钮。
class Button:def render(self):passclass WindowsButton(Button):def render(self):print("Rendering Windows style button.")class LinuxButton(Button):def render(self):print("Rendering Linux style button.")class ButtonFactory:@staticmethoddef get_button(os_type):if os_type == 'Windows':return WindowsButton()elif os_type == 'Linux':return LinuxButton()else:raise ValueError("Invalid OS type")# 客户端代码
button = ButtonFactory.get_button('Linux')
button.render()
API客户端:
当应用程序需要与多个外部服务或API交互时,可以使用简单工厂模式来创建针对每个服务的API客户端实例。这种方式便于管理和维护与各个服务的交互逻辑。
#有多个外部服务,根据服务类型创建对应的API客户端实例。
class APIClient:def fetch_data(self):passclass ServiceA_APIClient(APIClient):def fetch_data(self):print("Fetching data from Service A")class ServiceB_APIClient(APIClient):def fetch_data(self):print("Fetching data from Service B")class APIClientFactory:@staticmethoddef get_api_client(service_type):if service_type == 'ServiceA':return ServiceA_APIClient()elif service_type == 'ServiceB':return ServiceB_APIClient()else:raise ValueError("Invalid service type")# 客户端代码
api_client = APIClientFactory.get_api_client('ServiceA')
api_client.fetch_data()
支付方式处理:
在电子商务系统中,根据用户选择的支付方式(如信用卡支付、支付宝、微信支付等),使用简单工厂模式动态创建对应的支付处理对象。这样可以轻松扩展新的支付方式,同时保持代码的清晰和可维护性。
#电子商务系统中,根据用户选择的支付方式处理支付。
class PaymentProcessor:def process_payment(self, amount):passclass CreditCardProcessor(PaymentProcessor):def process_payment(self, amount):print(f"Processing ${amount} payment through Credit Card.")class PayPalProcessor(PaymentProcessor):def process_payment(self, amount):print(f"Processing ${amount} payment through PayPal.")class PaymentProcessorFactory:@staticmethoddef get_payment_processor(method):if method == 'CreditCard':return CreditCardProcessor()elif method == 'PayPal':return PayPalProcessor()else:raise ValueError("Invalid payment method")# 客户端代码
payment_processor = PaymentProcessorFactory.get_payment_processor('PayPal')
payment_processor.process_payment(100)
使用场景总结:
- 当需要根据输入或条件创建多个类的实例时,而这些类又有共同的父类或接口。
- 当创建对象的逻辑比较复杂,但又希望对客户端隐藏这些复杂性时。
- 当系统需要灵活地添加新产品时,而不希望对现有代码造成太大影响。