网站首页 > 技术文章 正文
1.1 设计模式的概念
设计模式,简单来说,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它就像是建筑领域里的经典建筑设计方案,针对不同类型的建筑需求(如住宅、商业大楼、学校等),都有对应的成熟设计方案。在软件开发中,设计模式描述了在软件设计过程中一些不断重复发生的问题,以及针对这些问题的解决方案。
例如,在开发一个电商系统时,购物车功能的实现就涉及到如何管理商品的添加、删除、计算总价等问题。而设计模式中就有相应的模式来指导我们如何优雅地构建购物车模块,使其具备良好的扩展性、维护性和复用性。
1.2 设计模式四要素
1.2.1 模式名称(pattern name)
模式名称是一个助记名,它用一两个词来描述模式的问题、解决方案和效果。好的模式名称能够让人快速联想到该模式所解决的核心问题。比如 “单例模式”,从名字就能知道,这个模式和确保一个类只有一个实例相关。当开发一个数据库连接池时,我们希望整个系统中只有一个连接池实例,以避免资源的浪费和管理的复杂性,这时 “单例模式” 这个名称就清晰地指向了对应的解决方案。
1.2.2 问题(problem)
问题描述了应该在何时使用模式。它详细说明了在软件开发过程中遇到的特定场景和问题。例如在游戏开发中,需要创建不同类型的角色,如战士、法师、刺客等,每个角色都有不同的属性和行为。此时,如何创建这些角色,并且使得角色的创建过程易于管理和扩展,就是一个实际问题。而工厂方法模式就能很好地解决这个问题,它定义了一个用于创建对象的接口,让子类决定实例化哪个类。
1.2.3 解决方案(solution)
解决方案描述了设计的组成成分,它们之间的相关关系以及各自的职责和协作方案。继续以上述游戏角色创建为例,使用工厂方法模式的解决方案可能是:定义一个抽象的角色工厂类,其中包含一个抽象的创建角色方法。然后为每种具体的角色(战士、法师、刺客)创建对应的具体工厂类,这些具体工厂类继承自抽象角色工厂类,并实现创建角色的方法。在客户端代码中,通过调用具体工厂类的创建方法来获取所需的角色对象。通过这样的设计,各个类之间的职责明确,协作有序,使得角色创建过程变得清晰且易于维护。
1.2.4 效果(consequences)
效果描述了模式应用的效果以及使用模式应该权衡的问题。例如,使用单例模式虽然确保了一个类只有一个实例,节省了系统资源,但是在多线程环境下,如果不进行适当的同步处理,可能会导致单例对象被多次创建,从而引发错误。再比如,使用代理模式可以在访问一个对象时添加额外的控制逻辑,如权限验证,但同时也会增加系统的复杂性和一定的性能开销。所以在使用设计模式时,需要根据具体的业务场景和需求,仔细权衡模式带来的效果和可能存在的问题。
1.3 设计模式分类
设计模式大致可以分为三类:创建型模式、结构型模式和行为型模式。
1.3.1 创建型模式(5 个)
创建型模式与对象的创建有关,它将对象的创建与使用分离。就好比在一家汽车制造工厂中,有专门负责生产汽车的车间(创建对象),而销售部门(使用对象)不需要了解汽车具体是如何生产的,只需要从生产车间获取成品汽车即可。常见的创建型模式有:
- 单例模式:确保一个类只有一个实例,并提供一个全局访问点。在一个系统中,日志记录器通常只需要一个实例,因为多个日志记录器可能会导致日志文件混乱。通过单例模式,我们可以保证整个系统中只有一个日志记录器实例,方便对日志进行统一管理。
- 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。例如在一个图形绘制系统中,有圆形、矩形、三角形等多种图形。我们可以定义一个图形工厂的抽象类,其中包含一个创建图形的抽象方法。然后为每种图形创建对应的具体工厂类,如圆形工厂类、矩形工厂类等,这些具体工厂类实现创建图形的方法。这样,当需要创建某种图形时,只需要调用相应的具体工厂类的创建方法即可,而不需要在客户端代码中编写复杂的对象创建逻辑。
- 抽象工厂模式:提供一个创建一组相关或相互依赖的对象的接口,不需要指定它们的具体类。比如在一个游戏开发中,需要创建不同风格的游戏角色、武器和装备。我们可以定义一个抽象工厂类,其中包含创建角色、武器和装备的抽象方法。然后针对不同的游戏风格(如中世纪风格、未来科幻风格等)创建对应的具体工厂类,这些具体工厂类实现创建相应风格角色、武器和装备的方法。通过这种方式,游戏开发者可以轻松切换游戏风格,而不需要大量修改客户端代码。
1.3.2 结构型模式(7 个)
结构型模式与对象的组装有关,它将类或对象按某种布局组成更大的结构。就如同搭建积木,我们通过不同的方式将各种形状的积木组合在一起,形成一个完整的结构。常见的结构型模式有:
- 适配器模式:将一个类的接口转换成客户希望的另一个接口。比如有一个旧的支付系统接口,而新的业务需求需要使用一种新的支付接口格式。这时可以使用适配器模式,创建一个适配器类,将旧支付系统接口适配成新的接口格式,使得新的业务代码能够顺利调用旧的支付系统。
- 桥模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。例如在一个图形绘制系统中,有不同的图形(圆形、矩形等),同时有不同的绘制方式(在屏幕上绘制、打印到纸张上等)。使用桥模式,可以将图形的抽象部分(如圆形、矩形的定义)与绘制方式的实现部分分离,这样当需要添加新的图形或者新的绘制方式时,只需要在各自的部分进行修改,而不会影响到对方。
- 组合模式:将对象组合成树形结构以表示 “部分 - 整体” 的层次结构。例如在一个文件系统中,文件和文件夹可以组成一个树形结构。文件夹可以包含文件和子文件夹,而文件是树形结构的叶子节点。通过组合模式,我们可以统一地对文件和文件夹进行操作,如遍历整个文件系统、计算文件夹大小等。
1.3.3 行为型模式(11 个)
行为型模式与类或对象之间的沟通协调有关,它描述了类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责。就像一场足球比赛,球员们(对象)之间需要相互配合(协作),各自承担不同的职责(进攻、防守、组织等),才能赢得比赛。常见的行为型模式有:
- 解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。例如在一个简单的数学表达式解析器中,需要对诸如 “3 + 5 * 2” 这样的数学表达式进行解析和计算。通过解释器模式,可以定义数学表达式的文法规则(如运算符的优先级、数字的表示等),并创建相应的解释器来解析和计算表达式。
- 责任链模式:为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。比如在一个请假审批系统中,请假申请可能需要经过不同层级的领导审批,如组长、部门经理、总经理等。使用责任链模式,可以将这些领导组成一条审批链,请假申请从链的一端开始传递,直到有领导批准或拒绝该申请。
- 命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。例如在一个图形编辑软件中,用户的操作(如绘制图形、移动图形、删除图形等)可以被封装成命令对象。这样可以方便地对用户操作进行记录、撤销和重做,同时也使得软件的扩展性更好,比如可以很容易地添加新的操作命令。
1.4 设计原则 - SOLID 原则
1.4.1 单一职责原则(Single Responsibility Principle)
单一职责原则要求每一个类实现的职责有清晰明确的定义,即一个类应该只有一个引起它变化的原因。比如有一个类UserInfo,它既负责获取用户的基本信息(如姓名、年龄、性别),又负责将用户信息保存到数据库中。如果未来需求发生变化,比如数据库存储格式改变,那么UserInfo类就需要修改;或者获取用户信息的方式改变,UserInfo类也需要修改。这就违背了单一职责原则,因为这个类有两个不同的职责,任何一个职责的变化都可能影响到另一个职责。更好的设计是将获取用户信息和保存用户信息的职责分别放到两个不同的类中,如UserInfoGetter类负责获取用户信息,UserInfoSaver类负责保存用户信息。这样当某个职责发生变化时,只需要修改对应的类,而不会影响到其他类,从而提高了代码的维护性。
1.4.2 开放封闭原则(Open - Closed Principle)
开放封闭原则指软件实体(类、模块、函数等)应该可以扩展,但是不可以修改。通俗来说就是对于要增加的新功能或要调整的改动,尽量扩展新代码而不是修改已有代码。例如有一个计算图形面积的函数calculate_area,它目前支持计算圆形和矩形的面积。如果未来需要支持计算三角形的面积,按照开放封闭原则,不应该直接修改calculate_area函数的代码,而是应该扩展新的代码。可以定义一个新的三角形面积计算类Triangle,实现计算三角形面积的方法,然后在calculate_area函数中增加对三角形的判断和处理逻辑,这样既实现了功能扩展,又没有修改原有的代码,保证了原有代码的稳定性。
1.4.3 里氏替换原则(Liskov Substitution Principle)
里氏替换原则确保父类能够真正复用(继承),子类也能够在父类的基础上增加新的行为。父类一般使用抽象类或接口,抽象类定义公共对象和状态,接口定义公共行为。例如有一个抽象的图形类Shape,其中定义了一个计算面积的抽象方法calculate_area。圆形类Circle和矩形类Rectangle继承自Shape类,并实现了calculate_area方法。在使用时,可以将Circle和Rectangle对象当作Shape对象来使用,因为它们满足里氏替换原则。子类方法的异常必须与父类能抛出的异常(或其子类)相匹配,这样才能保证在替换时程序的正确性和稳定性。
1.4.4 接口隔离原则(Interface Segregation Principle)
接口隔离原则要求客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。比如有一个接口AnimalActions,其中定义了飞行、游泳、奔跑等方法。对于鸟类,可能需要实现飞行和奔跑方法;对于鱼类,可能需要实现游泳方法。如果让鸟类和鱼类都实现AnimalActions接口,那么鱼类就依赖了它不需要的飞行和奔跑接口。更好的设计是将AnimalActions接口拆分成多个小接口,如Flyable接口(包含飞行方法)、Swimmable接口(包含游泳方法)、Runnable接口(包含奔跑方法),然后让鸟类实现Flyable和Runnable接口,鱼类实现Swimmable接口,这样就符合接口隔离原则,降低了类之间的耦合度。
1.4.5 依赖倒置原则(Dependency Inversion Principle)
依赖倒置原则指抽象不应该依赖细节,细节应该依赖抽象。高层模块不应该依赖低层模块,二者都应该依赖抽象。例如在一个电商系统中,有一个订单处理模块(高层模块)和一个数据库操作模块(低层模块)。如果订单处理模块直接依赖数据库操作模块的具体实现,那么当数据库操作方式发生变化时,订单处理模块也需要大量修改。按照依赖倒置原则,应该定义一个抽象的数据库操作接口,订单处理模块依赖这个抽象接口,而具体的数据库操作类实现这个接口。这样当数据库操作方式改变时,只需要修改具体的数据库操作类,而订单处理模块不需要修改,提高了系统的可维护性和扩展性。
通过遵循 SOLID 原则,可以指导程序员开发出易于维护和扩展的软件,为使用设计模式打下坚实的基础。在后续章节中,我们将深入学习各种具体的设计模式,看看它们是如何体现这些设计原则的。
1.5 设计模式的实际应用场景
设计模式并非孤立存在,在实际软件开发中,往往需要根据具体业务场景选择合适的模式组合使用。以下从不同行业领域和系统模块角度,介绍设计模式的典型应用场景。
1.5.1 互联网电商领域
在互联网电商系统中,设计模式的应用十分广泛:
- 订单处理模块:订单从创建到支付完成、发货、售后的整个流程,涉及多个步骤的协作和状态变化。这里可以结合状态模式和责任链模式。使用状态模式管理订单的不同状态(如待支付、已支付、已发货、已完成、售后中),每个状态对应不同的行为和状态转换规则,例如待支付状态下用户可以支付订单,支付完成后订单状态转换为已支付;同时,订单的审核流程(如普通订单无需审核、大额订单需财务审核、特殊商品订单需风控审核)可以使用责任链模式,将不同的审核节点组成一条链,订单依次经过各节点审核,直至完成所有审核或被驳回。
- 商品推荐模块:为了给用户推荐个性化的商品,需要根据用户的浏览历史、购买记录、兴趣标签等多种因素进行计算。这里可以使用策略模式,将不同的推荐算法(如基于协同过滤的推荐、基于内容的推荐、基于热门商品的推荐)封装成不同的策略类。系统可以根据用户的类型(如新用户、老用户、高消费用户)或业务需求(如促销活动期间优先推荐促销商品),动态选择对应的推荐策略,从而实现灵活的推荐功能。
1.5.2 企业管理系统领域
企业管理系统(如 ERP 系统、OA 系统)通常业务逻辑复杂,对数据的安全性、一致性和系统的可扩展性要求较高:
- 数据访问模块:由于企业数据可能存储在不同的数据库(如 MySQL、Oracle、SQL Server)中,且数据访问操作(增删改查)频繁。这里可以结合抽象工厂模式和工厂方法模式。使用抽象工厂模式定义一组用于创建不同数据库连接和数据操作对象的接口,例如DBConnectionFactory(数据库连接工厂)和DBOperationFactory(数据操作工厂),然后为每种数据库创建对应的具体工厂类,如MySQLConnectionFactory、OracleConnectionFactory等。同时,在数据操作的具体实现中,可以使用工厂方法模式创建不同的数据操作对象(如UserDBOperation、OrderDBOperation),使得数据访问模块能够灵活适配不同的数据库,且便于后续添加新的数据库支持。
- 权限管理模块:企业管理系统中,不同角色的用户拥有不同的操作权限(如普通员工只能查看和修改自己的数据,部门经理可以查看和管理部门内所有员工的数据,系统管理员拥有所有操作权限)。这里可以使用代理模式和组合模式。使用代理模式为每个业务对象(如用户数据对象、订单数据对象)创建代理对象,在代理对象中添加权限验证逻辑,只有当用户拥有相应权限时,才允许访问或操作业务对象;同时,使用组合模式将用户、部门、角色等权限相关的元素组合成树形结构,如部门包含多个用户和子部门,角色包含多个权限点,通过树形结构可以方便地管理和查询用户的权限范围,例如查询某个部门下所有用户的权限总和。
1.6 Python 中实现设计模式的优势
Python 作为一种动态、面向对象的编程语言,其独特的语言特性为实现设计模式提供了诸多便利,使得设计模式在 Python 中的应用更加灵活和简洁。
1.6.1 动态类型特性简化接口定义
在 Java、C# 等静态类型语言中,实现设计模式时往往需要定义大量的接口和抽象类来约束类的结构和行为。而 Python 是动态类型语言,不需要显式定义接口,通过 “鸭子类型”(Duck Typing)即可实现类似接口的功能。例如在实现工厂方法模式时,不需要像静态类型语言那样先定义一个抽象的产品接口,再让具体产品类实现该接口,而是直接定义具体产品类,并确保它们拥有相同的方法名和行为即可。客户端代码在使用产品对象时,只需要调用相应的方法,而无需关心对象的具体类型,从而简化了代码结构,减少了冗余的接口定义代码。
以下是一个简单的示例,展示了 Python 中利用动态类型特性实现工厂方法模式的简洁性:
# 具体产品类 - 圆形
class Circle:
def draw(self):
print("绘制圆形")
# 具体产品类 - 矩形
class Rectangle:
def draw(self):
print("绘制矩形")
# 具体工厂类 - 圆形工厂
class CircleFactory:
def create_shape(self):
return Circle()
# 具体工厂类 - 矩形工厂
class RectangleFactory:
def create_shape(self):
return Rectangle()
# 客户端代码
def client_code(factory):
shape = factory.create_shape()
shape.draw()
# 使用圆形工厂创建圆形并绘制
circle_factory = CircleFactory()
client_code(circle_factory) # 输出:绘制圆形
# 使用矩形工厂创建矩形并绘制
rectangle_factory = RectangleFactory()
client_code(rectangle_factory) # 输出:绘制矩形
从上述代码可以看出,Python 中没有定义专门的产品接口,而是通过确保Circle和Rectangle类都拥有draw方法,实现了类似接口的约束效果,客户端代码可以统一调用draw方法,代码更加简洁直观。
1.6.2 装饰器简化代理、装饰等模式实现
Python 的装饰器(Decorator)是一种特殊的语法结构,它可以在不修改原有函数或类代码的前提下,为其添加额外的功能。这一特性使得实现代理模式、装饰模式等变得非常方便。
例如,在实现代理模式时,我们可以使用装饰器为目标对象添加权限验证、日志记录等额外功能,而无需创建专门的代理类。以下是一个使用装饰器实现代理模式(权限验证)的示例:
def permission_check_decorator(func):
def wrapper(user, *args, **kwargs):
# 模拟权限验证逻辑,假设只有管理员用户拥有访问权限
if user == "admin":
return func(*args, **kwargs)
else:
raise PermissionError("您没有访问该功能的权限")
return wrapper
# 目标对象 - 敏感数据操作类
class SensitiveDataOperator:
@permission_check_decorator
def get_sensitive_data(self):
return "这是敏感数据:xxx-xxx-xxx"
# 客户端代码
operator = SensitiveDataOperator()
# 管理员用户访问
try:
data = operator.get_sensitive_data("admin")
print(data) # 输出:这是敏感数据:xxx-xxx-xxx
except PermissionError as e:
print(e)
# 普通用户访问
try:
data = operator.get_sensitive_data("user")
print(data)
except PermissionError as e:
print(e) # 输出:您没有访问该功能的权限
在上述代码中,
permission_check_decorator装饰器为SensitiveDataOperator类的get_sensitive_data方法添加了权限验证功能,实现了代理模式的核心思想(在访问目标对象时添加额外控制逻辑),但相比传统的创建代理类的方式,代码更加简洁,且易于维护和扩展。如果后续需要添加其他额外功能(如日志记录),只需要再定义一个相应的装饰器并应用到目标方法上即可。
1.6.3 内置数据结构与设计模式的契合
Python 提供了丰富的内置数据结构,如列表(list)、字典(dict)、集合(set)等,这些数据结构的特性与某些设计模式的思想高度契合,可以直接用于实现设计模式,减少代码的开发量。
例如,在实现组合模式时,由于组合模式需要将对象组合成树形结构,而 Python 的列表可以很方便地存储子节点对象,从而构建树形结构。以下是一个使用列表实现文件系统(组合模式)的示例:
# 抽象组件类 - 文件系统节点
class FileSystemNode:
def __init__(self, name):
self.name = name
def get_size(self):
raise NotImplementedError("子类必须实现get_size方法")
# 叶子节点类 - 文件
class File(FileSystemNode):
def __init__(self, name, size):
super().__init__(name)
self.size = size
def get_size(self):
return self.size
# 复合节点类 - 文件夹
class Folder(FileSystemNode):
def __init__(self, name):
super().__init__(name)
self.children = [] # 使用列表存储子节点(文件或文件夹)
def add_child(self, child):
self.children.append(child)
def remove_child(self, child):
self.children.remove(child)
def get_size(self):
# 文件夹的大小等于所有子节点大小之和
total_size = 0
for child in self.children:
total_size += child.get_size()
return total_size
# 客户端代码
# 创建文件
file1 = File("document1.txt", 1024)
file2 = File("image1.jpg", 2048)
file3 = File("video1.mp4", 10240)
# 创建文件夹并添加子节点
folder1 = Folder("work")
folder1.add_child(file1)
folder2 = Folder("media")
folder2.add_child(file2)
folder2.add_child(file3)
root_folder = Folder("root")
root_folder.add_child(folder1)
root_folder.add_child(folder2)
# 计算各节点大小
print(f"文件document1.txt大小:{file1.get_size()}字节") # 输出:文件document1.txt大小:1024字节
print(f"文件夹work大小:{folder1.get_size()}字节") # 输出:文件夹work大小:1024字节
print(f"文件夹media大小:{folder2.get_size()}字节") # 输出:文件夹media大小:12288字节
print(f"根文件夹root大小:{root_folder.get_size()}字节") # 输出:根文件夹root大小:13312字节
在上述代码中,使用 Python 的列表children存储文件夹的子节点(文件或文件夹),通过add_child和remove_child方法可以方便地管理子节点,而get_size方法则通过遍历子节点列表计算文件夹的大小,完美契合了组合模式的思想,且代码简洁高效,充分利用了 Python 内置数据结构的优势。
1.7 设计模式学习与使用的常见误区
虽然设计模式对于提高软件设计质量和开发效率具有重要意义,但在学习和使用过程中,很容易陷入一些误区,反而影响软件的开发。
1.7.1 过度设计:为了使用模式而使用模式
有些开发者在学习了设计模式后,会盲目地在项目中使用设计模式,即使是简单的功能也强行套用复杂的模式,导致代码结构冗余、可读性降低、开发效率下降。例如,对于一个只需要创建一种类型对象的简单场景,明明可以直接使用__init__方法创建对象,却非要使用工厂方法模式甚至抽象工厂模式,增加了不必要的类和接口定义,使得代码变得复杂。
避免这种误区的关键在于,要根据实际业务需求和系统复杂度来决定是否使用设计模式。在开发初期,如果系统功能简单、需求明确且未来变化可能性较小,应优先选择简单直接的实现方式;当系统功能逐渐复杂、需求变化频繁,且出现了设计模式所解决的典型问题时,再考虑引入合适的设计模式。
1.7.2 忽视语言特性:生搬硬套其他语言的模式实现
不同的编程语言具有不同的语法特性和设计理念,设计模式在不同语言中的实现方式也应有所差异。有些开发者在 Python 中实现设计模式时,完全照搬 Java、C# 等静态类型语言的实现方式,忽视了 Python 的动态类型、装饰器、内置数据结构等特性,导致代码冗长、不符合 Python 的编程风格。
例如,在 Java 中实现单例模式时,需要考虑多线程同步问题,并通过私有构造方法、静态私有成员变量和静态公有获取方法来确保单例;而在 Python 中,由于 GIL(全局解释器锁)的存在,在多线程环境下创建单例的方式与 Java 有所不同,且可以利用 Python 的模块导入机制(Python 模块在导入时只会被执行一次)来更简洁地实现单例模式,无需像 Java 那样编写复杂的同步代码。
因此,在 Python 中学习和使用设计模式时,应充分结合 Python 的语言特性,选择最符合 Python 风格的实现方式,以达到简化代码、提高效率的目的。
1.7.3 忽略模式的适用条件:盲目套用模式
每种设计模式都有其特定的适用条件和场景,只有在满足这些条件的情况下,使用设计模式才能带来好处。如果忽视模式的适用条件,盲目套用模式,不仅无法解决实际问题,还可能引入新的问题。
例如,责任链模式适用于请求需要经过多个对象处理,且不确定具体哪个对象会处理该请求的场景。如果在请求只能由一个特定对象处理,且处理流程固定的场景中使用责任链模式,会增加请求传递的开销和系统的复杂性,反而不如直接调用该特定对象的处理方法高效。
为了避免这种误区,开发者需要深入理解每种设计模式的适用条件、核心思想和解决的问题,在实际应用中,先分析业务场景是否符合模式的适用条件,再决定是否使用该模式。
1.8 本章小结
本章从设计模式的基本概念入手,详细介绍了设计模式的四要素(模式名称、问题、解决方案、效果),并对设计模式进行了分类(创建型模式、结构型模式、行为型模式),阐述了每类模式的核心思想和典型应用场景。同时,重点讲解了 SOLID 设计原则,这些原则是设计模式的基础,能够指导开发者设计出易于维护和扩展的软件系统。
此外,本章还补充了设计模式的实际应用场景,展示了设计模式在互联网电商和企业管理系统等领域的具体应用;分析了 Python 中实现设计模式的优势,包括动态类型特性简化接口定义、装饰器简化代理和装饰模式实现、内置数据结构与设计模式的契合等;最后指出了设计模式学习与使用的常见误区,并给出了避免这些误区的建议。
通过本章的学习,读者应该对设计模式有一个全面的认识,理解设计模式的重要性和核心思想,掌握 SOLID 设计原则,并了解 Python 中实现设计模式的特点和注意事项。在后续章节中,我们将按照创建型模式、结构型模式、行为型模式的顺序,逐一深入学习每种具体设计模式的定义、实现方式、应用场景和优缺点,帮助读者在实际项目中能够灵活运用设计模式解决问题。
猜你喜欢
- 2025-09-02 Druid 1.2.4 版本发布,增强对 JDK 8 的支持
- 2025-09-02 RAD Studio 、Delphi或C++Builder设计代码编译上线缩短开发时间
- 2024-11-10 测试用例:多线程图片ETL Oracle和S3
- 2024-11-10 连接池之HikariCP:HikariCP框架设计与功能使用分析(第一部分)
- 2024-11-10 深入Spring Boot (十六):从源码分析自动配置原理
- 2024-11-10 网关使用 Apache HttpClient 连接池出现异常
- 2024-11-10 Oracle TAC实战 oracle \t
- 2024-11-10 数据库连接池优化 数据库连接池调优
- 2024-11-10 重学MySQL:事务与连接池,一文详解带你搞懂
- 2024-11-10 咋回事!现在新人连数据库连接池c3p0都没有听说过?
你 发表评论:
欢迎- 最近发表
-
- Druid 1.2.4 版本发布,增强对 JDK 8 的支持
- Python设计模式 第 1 章 Python 设计模式概述
- RAD Studio 、Delphi或C++Builder设计代码编译上线缩短开发时间
- Hive如何比较两张表所有字段的一致性
- Java 中 java.util.Date 与 java.sql.Date 有什么区别?
- 主流CDC工具_cd软件是做什么的
- 19.提取HFM数据进数据库_怎么提取数据库的信息
- 将Spring Boot应用部署到 Azure_springboot部署到windows
- 这样优化Spring Boot,启动速度快到飞起
- 什么是便携式应用程序,为什么它很重要?
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- Oracle RAC (76)
- oracle恢复 (77)
- oracle 删除表 (52)
- oracle 用户名 (80)
- oracle 工具 (55)
- oracle 内存 (55)
- oracle 导出表 (62)
- oracle约束 (54)
- oracle 中文 (51)
- oracle链接 (54)
- oracle的函数 (58)
- oracle面试 (55)
- 前端调试 (52)
本文暂时没有评论,来添加一个吧(●'◡'●)