当前位置: 首页 > news >正文

基于类的四种设计模式

1. 工厂方法模式 (Factory Method)

问题

当系统需要创建对象,但具体类型在编译时无法确定,或者创建逻辑复杂需要封装时,直接使用new关键字会导致代码耦合度高、难以扩展。

解决方案

定义一个创建对象的接口,但让子类决定实例化哪个类。工厂方法让类的实例化推迟到子类。

组件框图

┌─────────────────┐         ┌──────────────────┐
│    Creator      │         │    Product       │
├─────────────────┤         ├──────────────────┤
│+factoryMethod() │───────>│                  │
└─────────────────┘         └──────────────────┘
▲                            ▲
│                            │
┌─────────────────┐         ┌──────────────────┐
│ ConcreteCreator │         │ ConcreteProduct  │
├─────────────────┤         ├──────────────────┤
│+factoryMethod() │         │                  │
└─────────────────┘         └──────────────────┘

效果

优点:

  • 符合开闭原则,易于扩展新产品

  • 客户端与具体产品类解耦

  • 将创建逻辑集中管理

缺点:

  • 每增加一个产品就需要增加一个具体工厂类

  • 增加了系统的复杂度

代码示例(Python重点展示)

from abc import ABC, abstractmethodclass Document(ABC):@abstractmethoddef open(self):pass@abstractmethoddef save(self):passclass WordDocument(Document):def open(self):print("打开Word文档")def save(self):print("保存Word文档")class PDFDocument(Document):def open(self):print("打开PDF文档")def save(self):print("保存PDF文档")class Application(ABC):def __init__(self):self.documents = []@abstractmethoddef create_document(self) -> Document:passdef new_document(self):doc = self.create_document()self.documents.append(doc)doc.open()return docclass WordApplication(Application):def create_document(self) -> Document:return WordDocument()class PDFApplication(Application):def create_document(self) -> Document:return PDFDocument()# 使用
app = WordApplication()
doc = app.new_document()  # 输出: 打开Word文档

2. 基于类的适配器模式 (Class Adapter)

问题

现有类的接口与客户端期望的接口不兼容,但需要让它们能够协同工作,且不希望修改现有代码。

解决方案

通过多重继承(或实现接口+继承)创建一个适配器类,它同时继承目标接口和被适配者,在适配器类中实现接口转换。

组件框图

┌─────────────────┐         ┌──────────────────┐
│    Client       │         │    Target        │
├─────────────────┤         ├──────────────────┤
│                 │───────>│+request()        │
└─────────────────┘         └──────────────────┘▲│┌──────────────────┐│    Adapter       │├──────────────────┤│+request()        │└──────────────────┘▲│┌──────────────────┐│   Adaptee        │├──────────────────┤│+specificRequest()│└──────────────────┘

效果

优点:

  • 可以让任何两个没有关联的类一起运行

  • 提高了类的复用性

  • 符合开闭原则

缺点:

  • 过多使用适配器会让系统变得混乱

  • 由于使用继承,限制了适配器的灵活性

代码示例(C++重点展示)

#include <iostream>
#include <string>// 目标接口 - 欧洲插座
class EuropeanSocket {
public:virtual ~EuropeanSocket() = default;virtual void plugIn() = 0;virtual int getVoltage() = 0;
};// 被适配者 - 美国插座
class AmericanSocket {
public:void connect() {std::cout << "美国插座连接" << std::endl;}int getUSVoltage() {return 110;  // 110V}
};// 适配器 - 旅行转换器
class SocketAdapter : public EuropeanSocket, private AmericanSocket {
public:void plugIn() override {std::cout << "使用适配器连接: ";connect();  // 调用被适配者的方法std::cout << "将电压从" << getUSVoltage() << "V转换到" << getVoltage() << "V" << std::endl;}int getVoltage() override {return 220;  // 转换为欧洲电压}
};// 欧洲电器
class EuropeanDevice {
public:void use(EuropeanSocket* socket) {socket->plugIn();std::cout << "设备在 " << socket->getVoltage() << "V 电压下工作" << std::endl;}
};// 使用
int main() {EuropeanDevice device;SocketAdapter adapter;device.use(&adapter);return 0;
}

3. 解释器模式 (Interpreter)

问题

需要解释执行特定语言或文法规则,且文法规则可以表示为层次结构。例如:正则表达式、数学表达式、SQL查询等。

解决方案

定义文法的类层次结构,每个规则对应一个类,通过组合模式构建抽象语法树,实现解释操作。

组件框图

┌─────────────────┐         ┌──────────────────┐
│   Client        │         │  AbstractExpression
├─────────────────┤         ├──────────────────┤
│                 │───────>│+interpret(Context)│
└─────────────────┘         └──────────────────┘△┌────────────────┼────────────────┐┌────────────┴────────────┐    ┌──────────────┴────────────┐│     TerminalExpression  │    │  NonterminalExpression    │├─────────────────────────┤    ├───────────────────────────┤│+interpret(Context)      │    │+interpret(Context)        │└─────────────────────────┘    │-expression                │└───────────────────────────┘

效果

优点:

  • 易于改变和扩展文法

  • 实现文法很容易,类层次结构清晰

  • 易于实现简单文法

缺点:

  • 复杂的文法难以维护

  • 执行效率较低

  • 类数量会随着规则增加而增加

代码示例(C#重点展示)

using System;
using System.Collections.Generic;// 上下文 - 存储变量值
public class Context
{private Dictionary<string, bool> variables = new Dictionary<string, bool>();public void SetVariable(string name, bool value){variables[name] = value;}public bool GetVariable(string name){return variables.ContainsKey(name) ? variables[name] : false;}
}// 抽象表达式
public interface IExpression
{bool Interpret(Context context);
}// 终结符表达式 - 变量
public class VariableExpression : IExpression
{private string name;public VariableExpression(string name){this.name = name;}public bool Interpret(Context context){return context.GetVariable(name);}
}// 终结符表达式 - 常量
public class ConstantExpression : IExpression
{private bool value;public ConstantExpression(bool value){this.value = value;}public bool Interpret(Context context){return value;}
}// 非终结符表达式 - 与操作
public class AndExpression : IExpression
{private IExpression left;private IExpression right;public AndExpression(IExpression left, IExpression right){this.left = left;this.right = right;}public bool Interpret(Context context){return left.Interpret(context) && right.Interpret(context);}
}// 非终结符表达式 - 或操作
public class OrExpression : IExpression
{private IExpression left;private IExpression right;public OrExpression(IExpression left, IExpression right){this.left = left;this.right = right;}public bool Interpret(Context context){return left.Interpret(context) || right.Interpret(context);}
}// 非终结符表达式 - 非操作
public class NotExpression : IExpression
{private IExpression expression;public NotExpression(IExpression expression){this.expression = expression;}public bool Interpret(Context context){return !expression.Interpret(context);}
}// 使用
class Program
{static void Main(){// 构建上下文:A=true, B=false, C=trueContext context = new Context();context.SetVariable("A", true);context.SetVariable("B", false);context.SetVariable("C", true);// 构建表达式: (A AND B) OR (NOT C)IExpression expression = new OrExpression(new AndExpression(new VariableExpression("A"),new VariableExpression("B")),new NotExpression(new VariableExpression("C")));bool result = expression.Interpret(context);Console.WriteLine($"表达式 (A AND B) OR (NOT C) 的结果: {result}");// 计算: (true AND false) OR (NOT true) = false OR false = false// 另一个表达式: A OR (B AND C)IExpression expression2 = new OrExpression(new VariableExpression("A"),new AndExpression(new VariableExpression("B"),new VariableExpression("C")));bool result2 = expression2.Interpret(context);Console.WriteLine($"表达式 A OR (B AND C) 的结果: {result2}");// 计算: true OR (false AND true) = true OR false = true}
}

4. 模板方法模式 (Template Method)

问题

多个类有相同的工作步骤,但某些步骤的具体实现不同。需要在保持算法结构不变的前提下,允许子类重新定义某些步骤。

解决方案

在抽象类中定义算法的骨架,将一些步骤的实现推迟到子类中。模板方法使得子类可以不改变算法结构的情况下重新定义算法的某些步骤。

组件框图

┌─────────────────┐
│ AbstractClass   │
├─────────────────┤
│+templateMethod()│
│+step1()         │
│+step2()         │
│#primitiveOp1()  │
│#primitiveOp2()  │
│#hook()          │
└─────────────────┘△│
┌─────────────────┐
│ ConcreteClass   │
├─────────────────┤
│#primitiveOp1()  │
│#primitiveOp2()  │
│#hook()          │
└─────────────────┘

效果

优点:

  • 代码复用,将不变行为移到超类

  • 符合开闭原则,易于扩展

  • 便于维护,算法结构集中管理

缺点:

  • 每个不同的实现都需要一个子类

  • 超类中的抽象方法必须由子类实现

  • 可能违反里氏替换原则

详细代码示例(Python)

from abc import ABC, abstractmethod
from datetime import datetimeclass ReportGenerator(ABC):"""报表生成器模板类"""def generate_report(self):"""模板方法 - 定义报表生成流程"""self.collect_data()self.process_data()self.format_report()if self.needs_export():self.export_report()self.cleanup()def collect_data(self):"""具体方法 - 收集数据(所有报表通用)"""print(f"[{datetime.now()}] 开始收集数据...")# 模拟数据收集self.data = ["数据1", "数据2", "数据3"]print("数据收集完成")@abstractmethoddef process_data(self):"""抽象方法 - 处理数据(子类必须实现)"""pass@abstractmethoddef format_report(self):"""抽象方法 - 格式化报表(子类必须实现)"""passdef export_report(self):"""钩子方法 - 导出报表(子类可选重写)"""print("默认导出为PDF格式")def needs_export(self):"""钩子方法 - 是否需要导出(子类可选重写)"""return Truedef cleanup(self):"""具体方法 - 清理资源(所有报表通用)"""print("清理临时数据和资源...")class SalesReportGenerator(ReportGenerator):"""销售报表生成器"""def process_data(self):"""实现销售数据处理的特定逻辑"""print("处理销售数据: 计算销售额、增长率等指标")self.processed_data = [f"销售指标: {item}" for item in self.data]def format_report(self):"""实现销售报表的特定格式"""print("格式化销售报表: 使用图表展示销售趋势")print("生成的报表内容:", self.processed_data)def export_report(self):"""重写导出方法 - 销售报表需要多种格式"""print("导出销售报表: PDF, Excel, 和HTML格式")class FinancialReportGenerator(ReportGenerator):"""财务报表生成器"""def process_data(self):"""实现财务数据处理的特定逻辑"""print("处理财务数据: 计算利润、资产负债表等项目")self.processed_data = [f"财务项目: {item}" for item in self.data]def format_report(self):"""实现财务报表的特定格式"""print("格式化财务报表: 使用表格展示财务数据")print("生成的报表内容:", self.processed_data)def needs_export(self):"""重写钩子方法 - 财务报表不需要自动导出"""return Falsedef audit_trail(self):"""财务报表特有的审计追踪方法"""print("生成审计追踪记录")class InventoryReportGenerator(ReportGenerator):"""库存报表生成器"""def process_data(self):"""实现库存数据处理的特定逻辑"""print("处理库存数据: 计算库存周转率、安全库存等")self.processed_data = [f"库存指标: {item}" for item in self.data]def format_report(self):"""实现库存报表的特定格式"""print("格式化库存报表: 使用条形图展示库存水平")print("生成的报表内容:", self.processed_data)def export_report(self):"""重写导出方法 - 库存报表需要实时同步"""print("导出库存报表并同步到ERP系统")# 客户端代码
def main():print("=== 销售报表生成 ===")sales_report = SalesReportGenerator()sales_report.generate_report()print("\n=== 财务报表生成 ===")financial_report = FinancialReportGenerator()financial_report.generate_report()print("\n=== 库存报表生成 ===")inventory_report = InventoryReportGenerator()inventory_report.generate_report()if __name__ == "__main__":main()

模式对比总结

模式主要目的适用场景关键特性
工厂方法对象创建解耦创建逻辑复杂或运行时确定类型子类决定创建对象
适配器模式接口转换集成不兼容的接口继承+接口实现
解释器模式语言解释特定领域语言处理文法类层次结构
模板方法算法骨架固定多个类有相同流程但不同实现抽象类定义模板

这些模式都体现了面向对象设计的重要原则:开闭原则、依赖倒置原则和里氏替换原则,在实际开发中可以根据具体需求灵活选用。

http://www.dtcms.com/a/427199.html

相关文章:

  • 用ChatGPT修改论文,如何在提升质量的同时降低AI检测风险?
  • 实验指导-基于阿里云Serverless应用引l擎SAE的服务部署迀移
  • 黔西县住房和城乡建设局网站个人网页制作方法
  • 长沙网站推广系统动态wordpress动态主题
  • 基于Matlab实现路径规划
  • 给定数据规模的ACM风格笔试题-子矩阵的最大累加和问题
  • 一站式服务图片wordpress博客整站源码
  • 明星粉丝网站怎么做建设银行手机银行官方网站下载安装
  • Spring boot中 限制 Mybatis SQL日志的大字段输出
  • SQL Server数据库事务日志问题的诊断与解法(从膨胀到瘦身)
  • Postgresql CLOG文件及其从库同步解析
  • wordpress 授权一个空间两个网站对seo
  • 正规的招聘网站永州市网站建设
  • 加强教育信息网站建设昆山建设工程安监站网站
  • EndoChat:面向内镜手术的基于事实依据的多模态大型语言模型|文献速递-文献分享
  • 零基础学AI大模型之ChatModel聊天模型与ChatPromptTemplate实战
  • 产生式规则对自然语言处理深层语义分析的影响与启示研究
  • web渗透之Python反序列化漏洞
  • 做办公用品网站工作计划黄页网站是什么
  • 论文阅读 (1) :Control Flow Management in Modern GPUs
  • 吉林省软环境建设网站网络营销属于哪个专业
  • iOS 26 系统流畅度检测 从视觉特效到帧率稳定的实战策略
  • 2025云栖大会,机器人商业时代降临
  • C++面向对象编程三大特性之一:多态
  • TapTalk | 圆桌实录:澳门综合度假村敏捷转型之旅,MongoDB + TapData 赋能酒店业卓越实践
  • 机器人市场:犹如一颗深水核弹
  • 用VS做的网站怎么连接数据库深圳人才招聘网官网
  • mysql_query函数:数据库世界的信使
  • 【最新】Navicat Premium 17
  • Eclipse Mosquitto MQTT 代理中持久性引擎(database.c 概念)的作用分析报告