详解51种企业应用架构模式

导读:企业应用包括哪些?它们又分别有哪些架构模式?世界著名软件开发大师Martin Fowler给你答案

一、什么是企业应用

我的职业生涯专注于企业应用,因此,这里所谈及的模式也都是关于企业应用的。(企业应用还有一些其他的说法,如“信息系统”或更早期的“数据处理”。)那么,这里的“企业应用”具体指的是什么呢?我无法给出一个精确的定义,但是我可以罗列一些个人的理解。

先举几个例子。企业应用包括工资单、患者记录、发货跟踪、成本分析、信用评分、保险、供应链、会计、客户服务以及外汇交易等。企业应用不包括汽车燃油喷射、文字处理、电梯控制、化工厂控制器、电话交换机、操作系统、编译器以及电子游戏等。

企业应用一般都涉及持久化数据。 数据必须持久化是因为程序的多次运行都需要用到它们——实际上,有些数据需要持久化若干年。在此期间,操作这些数据的程序往往会有很多变化。这些数据的生命周期往往比最初生成它们的那些硬件、操作系统和编译器还要长。在此期间,为了存储新的信息而不干扰旧的信息,数据的结构经常会发生许多变化。即使是有根本性的变化发生,或公司安装了一套全新的软件来处理某项任务,这些数据也必须被“迁移”到新的应用上。

企业应用一般都涉及大量数据——一个中等规模的系统往往都包含1GB以上的数据,这些数据是以数千万条记录的方式存在的。巨大的数据量导致数据的管理成为系统的主要工作。早期的系统使用的是索引文件结构,如IBM的VSAM和ISAM。现代的系统往往采用数据库,绝大多数是关系型数据库。设计和填充这些数据库已经成为一个独立的专业领域。

企业应用一般还涉及很多人并发访问数据。对于很多系统来说,人数可能在100人以下,但是对于一些通过互联网进行通信的基于Web的系统,人数则会呈指数级增长。要确保这些人都能够正确地访问数据,就一定会存在这样或那样的问题。即使人数没有那么多,要确保两个人在同时操作同一数据项时不出现错误,也是存在问题的。事务管理工具可以处理其中的一些负担,但是它通常无法做到对应用开发者隐藏。

企业应用还涉及大量操作数据的用户界面屏幕。有几百个用户界面屏幕是不足为奇的。企业应用的用户从偶尔使用到定期使用都有,他们也经常没什么技术背景。因此,出于不同的使用目的,数据需要很多种表现形式。系统一般都有很多批处理过程,但当专注于强调用户交互的用例时,这些批处理过程很容易被忽视。

企业应用很少独立存在,通常需要与散布在企业周围的其他企业应用集成。这些各式各样的系统是在不同时期采用不同技术构建的,甚至连协作机制都不同:COBOL数据文件、CORBA系统或是消息系统。企业经常希望能用一种统一的通信技术来集成所有系统。当然,每次这样的集成工作几乎都很难真正实现,所以会有几个不同的统一集成方案同时存在。当业务组织需要同其业务伙伴进行应用集成时,情况就更糟糕。

即使是某家公司统一了集成技术,它们也还是会遇到业务流程中的差异以及数据中概念的不一致性。一个部门可能认为客户是当前签有协议的人,而另外一个部门可能还要将那些以前有合同但现在已经没有了的人计算在内。再有,一个部门可能只关心产品销售而不关心服务销售。粗看起来,这些问题似乎容易解决,但是,一旦几百条记录中的每个字段都有可能存在着细微差别,问题的规模就会形成不小的挑战——就算唯一知道这些字段真正含义的员工还在公司任职(当然,所有这些都会毫无预警地发生变化)。这样,数据就必须被不停地以各种不同的语法和语义格式读取、转换和写入。

再接下来的问题是由“业务逻辑”带来的。我认为“业务逻辑”这个词很滑稽,因为很难再找出什么东西比“业务逻辑”更加没有逻辑。当我们构建一个操作系统时,总是尽可能地使得系统中的各种事物符合逻辑。而业务规则是人家给你的,没有相当的行政努力,不要想改变它,当然,它们都有自己的理由。你必须面对很多奇怪的条件,而且这些条件相互作用的方式也非常怪异。比如,某个销售人员为了签下其客户几百万美元的一张单,可能会在商务谈判中与对方达成协议,将该项目的年度到账时间推迟两天,因为这样才能够与该客户的账务周期相吻合。成千上万的这类“一次性特殊情况”最终导致了复杂的业务“无逻辑”,使得商业软件开发那么困难。在这种情况下,必须尽量将这些业务逻辑组织成有效的方式,因为我们可以确定的是,这些“逻辑”一定会随着时间不断变化。

图片

▲对不同的领域逻辑组织方式,领域逻辑的复杂度和工作量之间的关系示意

对于一些人来说,“企业应用”这个术语指的是大型系统。但是记住这一点很重要:并不是所有的企业应用都是大型的,尽管它们可能都为企业提供巨大的价值。很多人认为,由于小型系统的规模不大,所以不值得为之操心,在某种程度上,这是合理的。如果一个小型系统失败了,它通常不会像大型系统那样引起广泛关注。但是,我认为这种思想没有对小型项目的累积效应给予足够的重视。试想,如果在小型项目上能够进行某些改善措施,那么这种累积效应对企业的影响是非常显著的,特别是因为小型项目通常具有不成比例的价值。实际上,你可以做的最好的事情之一是通过简化架构和过程,将一个大型项目变成小型项目。

二、企业应用的种类

在我们讨论如何设计企业应用以及使用哪些模式之前,认识到这一点很重要:企业应用是多种多样的,不同的问题将导致不同的处理方法。如果有人说,“总是这样做”的时候,就应当敲响警钟了。我认为,设计中最具挑战性(也是我最感兴趣)的地方就是了解有哪些候选的设计方案以及各种不同设计方案之间的优劣比较。进行选择的空间很大,但我在这里只选三个方面。

考虑一个B2C(Business to Customer)的在线零售商:人们浏览和——运气好,还有购物车——购买。这样一个系统必须能够应付大量的用户,因此,其解决方案不但要考虑到资源利用的高效,还要考虑到系统的可伸缩性,以便在用户规模增大时能够通过增加硬件的办法加以解决。这样的应用的领域逻辑可能非常直接:获取订单,进行简单的价格计算和发货计算,给出发货通知。我们希望任何人都能够轻松访问该系统,因此用户界面可以选用通用的Web表现方式,以支持各种不同的浏览器。数据源包括用来存放订单的数据库,还可能包括某种与库存系统的通信交流,以便获得商品的可用性信息和发货信息。

再考虑一个租约自动处理系统。在某些方面,这样的系统比起前面介绍的B2C零售商系统要简单得多,因为它的用户数很少(在特定时间内不会超过100个),但是它的业务逻辑却比较复杂。计算每个租约的月供,处理诸如提早解约和逾期付款这样的事件,签订合同时验证各种数据,这些都是复杂的任务,因为租约行业的许多竞争都是以过去的交易为基础稍加变化而出现的。正是因为规则的随意性很大,才使得像这样一个复杂的业务领域具有挑战性。

这样的系统在用户界面(UI)上也更加复杂。这就要求HTML界面要能提供更丰富的功能和更复杂的屏幕,而这些要求往往是HTML前端目前无法达到的,需要更传统的富客户界面。用户交互的复杂性还会带来事务行为的复杂性:签订租约可能要耗时1~2小时,这期间用户要处于一个逻辑事务中。一个复杂的数据库设计方案中可能也会涉及200多个表以及一些有关资产评估和计价的软件包。

第三个例子是一家小型公司使用的简单的“开支跟踪系统”。这个系统的用户很少,逻辑简单,并且可以通过HTML表示轻松地在整个公司访问,唯一的数据源是数据库中的几个表。尽管如此,开发这样的系统也不是没有挑战。一方面你必须快速地开发出它,另一方面你又必须为它以后可能的发展考虑:也许以后会为它增加计算报销支票的功能,也许它会被集成到工资系统中,也许还要增加关于税务的功能,也许要为公司的CFO生成汇总报表,也许会被集成到一个航空订票Web Service中,等等。如果在这个系统的开发中,也试图使用前面两个例子中的一些架构,可能会影响开发进度。如果一个系统会带来业务效益(如所有的企业应用应该的那样),则系统进度延误同样也是开销。你不希望现在做出的决策会阻碍未来的发展。但是,如果现在就考虑了这些灵活性但是考虑不得当,额外的复杂性又可能会让系统在未来变得更难演化,进一步延误系统部署,减少系统的效益。虽然这类系统很小,但是一个企业中往往有很多这样的系统,这些系统的架构不良性累积起来,后果将会非常可怕。

这三个企业应用的例子都有难点,而且难点各不相同。当然,也不可能有一个适合于三者的通用架构。选择架构时,必须很清楚地理解系统的特定问题,在理解的基础上再来选择合适的设计。

三、企业架构模式

模式的概念早就有了。我在这里不想把这段历史重新演绎一遍。只是想简单谈谈我对模式和它们为什么是描述设计的重要手段的一些看法。

模式没有统一的定义,可能最好的起点是Christopher Alexander给出的定义(这也是许多模式狂热者的灵感来源):

“每一个模式描述了一个在我们周围不断重复发生的问题以及该问题解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动”[Alexanderet al.]。

尽管Alexander是建筑家,他谈论的是建筑模式,但其定义也能很好地适用于软件业。模式的核心就是特定的解决方案,它有效而且有足够的通用性,能解决重复出现的问题。模式的另一种视角是把它看成一组建议,而创造模式的艺术则是将很多建议分解开来,形成相互独立的组,在此基础上可以相对独立地讨论它们。

模式的关键点是它们源于实践。必须观察人们的工作过程,发现其中好的设计,并找出“这些解决方案的核心”。这并不是一个简单的过程,但是一旦发现了某个模式,它将是非常有价值的。

一旦需要使用模式,就必须知道如何将它运用于当前的问题。使用模式的关键之一是不能盲目使用,这也是模式工具为什么都那么惨。我认为模式是一种“半生不熟品”,为了用好它,还必须在自己的项目中把剩下的那一半“火候”补上。我本人每次在使用模式时,都会东改一点西改一点。因此你会多次看到同一个解决方案,但没有一次是完全相同的。

每个模式相对独立,但又不彼此孤立。有时候它们相互影响,如影随形。

常见的企业系统架构模式包括三层架构、微服务架构和事件驱动架构。下面,我们介绍这些架构模式的特点,并通过代码示例来具体说明。

三层架构

三层架构是一种常见的企业系统架构模式,它将整个系统分为三个层次:表示层、业务逻辑层和数据访问层。表示层负责用户界面的展示,业务逻辑层负责处理具体的业务逻辑,数据访问层负责与数据库进行交互。这种架构模式能够提供灵活性和可维护性,便于系统的扩展和升级。

代码示例:

// 表示层
@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/list")
    public String listUsers(Model model) {
        List<User> users = userService.getAllUsers();
        model.addAttribute("users", users);
        return "user/list";
    }
}

// 业务逻辑层
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public List<User> getAllUsers() {
        return userDao.getAllUsers();
    }
}

// 数据访问层
@Repository
public class UserDao {
    public List<User> getAllUsers() {
        // 从数据库中获取所有用户数据
        // ...
    }
}

微服务架构

微服务架构是一种将系统拆分为多个小型、独立的服务的架构模式。每个微服务都是一个独立运行和部署的服务单元,它们通过轻量级的通信机制进行交互。微服务架构提供了高度可伸缩性和可扩展性,便于团队协作和系统维护。

代码示例:

// 用户服务微服务
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/{userId}")
    public User getUser(@PathVariable String userId) {
        return userService.getUser(userId);
    }
}

// 订单服务微服务
@RestController
@RequestMapping("/orders")
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/{orderId}")
    public Order getOrder(@PathVariable String orderId) {
        return orderService.getOrder(orderId);
    }
}

// 用户服务
@Service
public class UserService {
    public User getUser(String userId) {
        // 调用用户服务的数据库查询接口获取用户数据
        // ...
    }
}

// 订单服务
@Service
public class OrderService {
    public Order getOrder(String orderId) {
        // 调用订单服务的数据库查询接口获取订单数据
        // ...
    }
}

事件驱动架构

事件驱动架构是一种将系统设计为由事件驱动的架构模式。系统中的各个组件通过发布和订阅事件的方式进行通信,每个组件只需关注自己感兴趣的事件,从而提高系统的灵活性和可扩展性。事件驱动架构可以用于构建高度可伸缩的分布式系统。

代码示例:

// 事件发布者
@Component
public class EventPublisher {
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void publishEvent(Event event) {
        eventPublisher.publishEvent(event);
    }
}

// 事件订阅者
@Component
public class EventSubscriber implements ApplicationListener<Event> {
    @Override
    public void onApplicationEvent(Event event) {
        // 处理事件
        // ...
    }
}

// 事件
public class Event {
    // ...
}


四、好书推荐

《企业应用架构模式》一书中总结出的51种模式:

在这里插入图片描述

如果你是一个有经验的企业应用设计师,也许会对大多数模式都很熟悉。模式不是什么新鲜概念。因此,撰写模式书籍的作者也不会声称我们“发明”了某某模式,而是说我们“发现”了某某模式。我们的职责是记录通用的解决方案,找出其核心,并把最终的模式记录下来。对于一个高级设计师,模式的价值并不在于它给予你一些新东西,而在于它能帮助你更好地交流。如果你和你的同事都明白什么是远程外观,你就可以这样非常简捷地交流大量信息:“这个类是一个远程外观模式。”也可以对新人说:“用数据传输对象模式来解决这个问题。”模式为设计提供了一套词汇,这也是模式的名字如此重要的原因。

当你使用模式时请记住:它们只是开始,而不是结束。任何作者去囊括项目开发中的所有变化和技术是不可能的。我编写《企业应用架构模式》一书的目的也只是作为一个开始,希望它能够把我自己的和我所了解的经验和教训传递给读者,你们可以在此基础上继续努力。请大家记住:所有模式都是不完备的,你们都有责任在自己的系统中完善它们,你们也会在这个过程中得到乐趣。

在这里插入图片描述

关于作者:

马丁·福勒(Martin Fowler),世界著名软件开发大师,Thoughtworks首席科学家,从事软件开发相关工作30余年,是全球软件架构、敏捷开发、极限编程、设计模式等多个领域的领袖人物。此外,他在面向对象分析与设计、UML、数据库、领域特定语言等领域也有深厚的积累和卓越的贡献。

购书链接→:点此进入

文章目录

目  录Contents 译者序 前言 模式列表 引言 1
0.1 架构 1
0.2 企业应用 2
0.3 企业应用的种类 4
0.4 关于性能的考虑 5
0.5 模式 7
0.5.1 模式的结构 8
0.5.2 模式的局限性 9 第一部分 表  述 第1章 分层 12
1.1 企业应用中层次的演化 13
1.2 三个基本层次 14
1.3 为各层选择运行环境 16 第2章 组织领域逻辑 18
2.1 抉择 21
2.2 服务层 22 第3章 映射到关系数据库 24
3.1 架构模式 24
3.2 行为问题 28
3.3 读取数据 29
3.4 结构映射模式 30
3.4.1 关系的映射 30
3.4.2 继承 32
3.5 建立映射 34
3.6 使用元数据 35
3.7 数据库连接 36
3.8 其他问题 38
3.9 进一步阅读 38 第4章 Web表示层 39
4.1 视图模式 41
4.2 输入控制器模式 43
4.3 进一步阅读 44 第5章 并发 45
5.1 并发问题 46
5.2 执行语境 47
5.3 隔离与不变性 48
5.4 乐观并发控制和悲观并发控制 48
5.4.1 避免不一致读 49
5.4.2 死锁 50
5.5 事务 51
5.5.1 ACID 52
5.5.2 事务资源 52
5.5.3 减少事务隔离以提高灵活性 53
5.5.4 业务事务和系统事务 54
5.6 离线并发控制的模式 55
5.7 应用服务器并发 56
5.8 进一步阅读 57 第6章 会话状态 58
6.1 无状态的价值 58
6.2 会话状态 59
6.3 存储会话状态的方法 60 第7章 分布策略 63
7.1 分布对象的诱惑 63
7.2 远程接口和本地接口 64
7.3 必须使用分布的情况 65
7.4 关于分布边界 66
7.5 分布接口 67 第8章 通盘考虑 68
8.1 从领域层开始 69
8.2 深入到数据源层 70
8.2.1 事务脚本的数据源 70
8.2.2 表模块的数据源 70
8.2.3 领域模型的数据源 70
8.3 表示层 71
8.4 一些关于具体技术的建议 72
8.4.1 Java和J2EE 72
8.4.2 .NET 73
8.4.3 存储过程 73
8.4.4 Web Services 74
8.5 其他分层方式 74 第二部分 模  式 第9章 领域逻辑模式 78
9.1 事务脚本 78
9.1.1 运行机制 78
9.1.2 使用时机 79
9.1.3 收入确认问题 80
9.1.4 例:收入确认(Java) 81
9.2 领域模型 83
9.2.1 运行机制 84
9.2.2 使用时机 86
9.2.3 进一步阅读 86
9.2.4 例:收入确认(Java) 86
9.3 表模块 90
9.3.1 运行机制 91
9.3.2 使用时机 93
9.3.3 例:基于表模块的收入 确认(C#) 93
9.4 服务层 96
9.4.1 运行机制 97
9.4.2 使用时机 99
9.4.3 进一步阅读 100
9.4.4 例:收入确认(Java) 100 第10章 数据源架构模式 103
10.1 表数据入口 103
10.1.1 运行机制 103
10.1.2 使用时机 104
10.1.3 进一步阅读 105
10.1.4 例:人员入口(C#) 105
10.1.5 例:使用ADO.NET 数据集(C#) 107
10.2 行数据入口 109
10.2.1 运行机制 110
10.2.2 使用时机 110
10.2.3 例:人员记录(Java) 111
10.2.4 例:领域对象的数据 保持器(Java) 114
10.3 活动记录 115
10.3.1 运行机制 115
10.3.2 使用时机 116
10.3.3 例:一个简单的Person类 (Java) 116
10.4 数据映射器 118
10.4.1 运行机制 119
10.4.2 使用时机 122
10.4.3 例:一个简单的数据 映射器(Java) 123
10.4.4 例:分离查找器(Java) 127
10.4.5 例:创建一个空对象 (Java) 130 第11章 对象-关系行为模式 132
11.1 工作单元 132
11.1.1 运行机制 132
11.1.2 使用时机 136
11.1.3 例:使用对象注册的工作 单元(Java) 137
11.2 标识映射 140
11.2.1 运行机制 141
11.2.2 使用时机 143
11.2.3 例:标识映射中的方法 (Java) 143
11.3 延迟加载 144
11.3.1 运作机制 144
11.3.2 使用时机 146
11.3.3 例:延迟初始化(Java) 146
11.3.4 例:虚代理(Java) 147
11.3.5 例:使用值保持器(Java) 148
11.3.6 例:使用重影(C#) 149 第12章 对象-关系结构模式 156
12.1 标识字段 156
12.1.1 工作机制 156
12.1.2 使用时机 159
12.1.3 进一步阅读 160
12.1.4 例:整型键(C#) 160
12.1.5 例:使用键表(Java) 161
12.1.6 例:使用组合键(Java) 163
12.2 外键映射 172
12.2.1 运行机制 173
12.2.2 使用时机 175
12.2.3 例:单值引用(Java) 176
12.2.4 例:多表查询(Java) 178
12.2.5 例:引用集合(C#) 179
12.3 关联表映射 182
12.3.1 运行机制 182
12.3.2 使用时机 183
12.3.3 例:雇员和技能(C#) 183
12.3.4 例:使用直接的SQL (Java) 186
12.3.5 例:用一次查询查多个 雇员(Java) 189
12.4 依赖映射 193
12.4.1 运行机制 193
12.4.2 使用时机 194
12.4.3 例:唱片和曲目(Java) 195
12.5 嵌入值 197
12.5.1 运行机制 198
12.5.2 使用时机 198
12.5.3 进一步阅读 199
12.5.4 例:简单值对象(Java) 199
12.6 序列化LOB 200
12.6.1 运行机制 201
12.6.2 使用时机 201
12.6.3 例:在XML中序列化一个 部门层级(Java) 202
12.7 单表继承 204
12.7.1 运行机制 205
12.7.2 使用时机 205
12.7.3 例:运动员的单表(C#) 206
12.7.4 从数据库中加载对象 207
12.8 类表继承 210
12.8.1 运行机制 211
12.8.2 使用时机 211
12.8.3 进一步阅读 211
12.8.4 例:运动员和他们的 家属(C#) 212
12.9 具体表继承 216
12.9.1 运行机制 217
12.9.2 使用时机 218
12.9.3 例:具体运动员(C#) 219
12.10 继承映射器 223 ?12.10.1 运行机制 224 ?12.10.2 使用时机 225 第13章 对象-关系元数据映射 ?模式 226
13.1 元数据映射 226
13.1.1 运行机制 226
13.1.2 使用时机 228
13.1.3 例:使用元数据和反射 (Java) 228
13.2 查询对象 234
13.2.1 运行机制 234
13.2.2 使用时机 235
13.2.3 进一步阅读 236
13.2.4 例:简单的查询对象 (Java) 236
13.3 资源库 238
13.3.1 运行机制 239
13.3.2 使用时机 240
13.3.3 进一步阅读 241
13.3.4 例:查找一个人所在的 部门(Java) 241
13.3.5 例:资源库交换策略 (Java) 242 第14章 Web表现模式 243
14.1 模型-视图-控制器 243
14.1.1 运行机制 243
14.1.2 使用时机 245
14.2 页面控制器 245
14.2.1 运行机制 246
14.2.2 使用时机 247
14.2.3 例:Servlet控制器和JSP 视图的简单演示(Java) 247
14.2.4 例:使用JSP充当处理 程序(Java) 249
14.2.5 例:代码隐藏的页面 控制器(C#) 252
14.3 前端控制器 254
14.3.1 运行机制 255
14.3.2 使用时机 256
14.3.3 进一步阅读 257
14.3.4 例:简单的显示(Java) 257
14.4 模板视图 259
14.4.1 运行机制 260
14.4.2 使用时机 263
14.4.3 例:分离的控制器,使用 JSP充当视图(Java) 263
14.4.4 例:ASP.NET服务器 页面(C#) 265
14.5 转换视图 268
14.5.1 运行机制 268
14.5.2 使用时机 269
14.5.3 例:简单的转换(Java) 269
14.6 两步视图 271
14.6.1 运行机制 271
14.6.2 使用时机 272
14.6.3 例:两阶XSLT(XSLT) 276
14.6.4 例:JSP和定制标记 (Java) 278
14.7 应用控制器 282
14.7.1 运行机制 283
14.7.2 使用时机 284
14.7.3 进一步阅读 284
14.7.4 例:状态模型应用控制器 (Java) 284 第15章 分布模式 289
15.1 远程外观 289
15.1.1 运行机制 290
15.1.2 使用时机 292
15.1.3 例:使用Java语言的 会话bean来作为远程 外观(Java) 293
15.1.4 例:Web Service(C#) 295
15.2 数据传输对象 300
15.2.1 运行机制 300
15.2.2 使用时机 303
15.2.3 进一步阅读 304
15.2.4 例:传输唱片信息 (Java) 304
15.2.5 例:使用XML实现序列化 (Java) 308 第16章 离线并发模式 310
16.1 乐观离线锁 310
16.1.1 运行机制 310
16.1.2 使用时机 313
16.1.3 例:领域层与数据映射器 (Java) 314
16.2 悲观离线锁 317
16.2.1 运行机制 318
16.2.2 使用时机 321
16.2.3 例:简单锁管理对象 (Java) 321
16.3 粗粒度锁 326
16.3.1 运行机制 326
16.3.2 使用时机 328
16.3.3 例:共享的乐观离线锁 (Java) 328
16.3.4 例:共享的悲观离线锁 (Java) 333
16.3.5 例:根对象乐观离线锁 (Java) 333
16.4 隐含锁 334
16.4.1 运行机制 335
16.4.2 使用时机 335
16.4.3 例:隐含的悲观离线锁 (Java) 336 第17章 会话状态模式 338
17.1 客户会话状态 338
17.1.1 运行机制 338
17.1.2 使用时机 339
17.2 服务器会话状态 339
17.2.1 运行机制 340
17.2.2 使用时机 341
17.3 数据库会话状态 342
17.3.1 运行机制 342
17.3.2 使用时机 343 第18章 基本模式 344
18.1 入口 344
18.1.1 运行机制 345
18.1.2 使用时机 345
18.1.3 例:私有消息服务的入口 (Java) 346
18.2 映射器 349
18.2.1 运行机制 349
18.2.2 使用时机 350
18.3 层超类型 350
18.3.1 运行机制 350
18.3.2 使用时机 350
18.3.3 例:领域对象(Java) 350
18.4 分离接口 351
18.4.1 运行机制 352
18.4.2 使用时机 352
18.5 注册表 353
18.5.1 运行机制 353
18.5.2 使用时机 355
18.5.3 例:单例注册表(Java) 355
18.5.4 例:线程安全的注册表 (Java) 357
18.6 值对象 357
18.6.1 运行机制 358
18.6.2 使用时机 358
18.7 货币 359
18.7.1 运行机制 359
18.7.2 使用时机 361
18.7.3 例:货币类(Java) 361
18.8 特殊情况 365
18.8.1 运行机制 366
18.8.2 使用时机 366
18.8.3 进一步阅读 366
18.8.4 例:一个简单的空对象 (C#) 366
18.9 插件 367
18.9.1 运行机制 368
18.9.2 使用时机 369
18.9.3 例:ID生成器(Java) 369
18.10 服务桩 371 ?18.10.1 运行机制 372 ?18.10.2 使用时机 372 ?18.10.3 例:销售税服务(Java) 372
18.11 记录集 374 ?18.11.1 运行机制 375 ?18.11.2 使用时机 376 参考文献 377

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/680743.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

动态组件 commponted 怎么使用

优点&#xff1a; 提高代码复用性&#xff1a;通过将通用组件了逻辑封装在动态组件中&#xff0c;可以在多个地方重复使用&#xff0c;减少代码冗余。增强灵活性&#xff1a;动态组件可以根据不同的条件或状态动态切换显示内容&#xff0c;使用应用更加灵活和可定制。实现动态…

【外汇天眼】正确投资理念与心态:持续赚钱的秘诀

许多人心怀迅速致富的梦想&#xff0c;但同时又希望通过踏实的努力实现这一目标。他们既觉得为他人工作赚取收入过于辛苦&#xff0c;又认为自己创业当老板太过劳累。 实际上&#xff0c;赚钱的方式有很多种。有人凭借智慧和知识创造财富&#xff0c;有人依靠勤劳和技术赚取收…

当了程序员,才敢说的大实话(小白如何学好it)

&#x1f4e2;只有我真正当了程序员&#xff0c;才敢说出来的大实话。今天的内容&#xff0c;写给想学计算机和计算机专业的朋友们&#xff1a; . &#x1f340;数学课要学好&#xff0c;否则搞算法、AI的时候弄不好得再学一遍 &#x1f340;计算机基础知识很重要&#xff0c;只…

在无GPU的windows上运行ChatTTS

如果你在安装的过程中出现了下面的错误&#xff0c;不妨先看看这些安装步骤&#xff1a; cl: 命令行 error D8021 :无效的数值参数“/Wno-register” error: command C:\ windows ERROR: Failed building wheel for pynini 卷完了文本&#xff0c;卷图片&#xff0c;卷完了图…

MySQL——覆盖索引

覆盖索引介绍 理解方式一&#xff1a;索引是高效找到行的一个方法&#xff0c;但是一般数据库也能使用索引找到一个列的数据&#xff0c;因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据&#xff1b;当然通过读取索引就可以得到想要的数据&#xff0c;那就不需要…

【python】成功解决“SyntaxError: can’t assign to function call”错误的全面指南

成功解决“SyntaxError: can’t assign to function call”错误的全面指南 在Python编程中&#xff0c;语法错误&#xff08;SyntaxError&#xff09;是初学者和经验丰富的开发者都可能遇到的问题。其中&#xff0c;“SyntaxError: can’t assign to function call”这个错误常…

软件三班20240605

文章目录 1.创建工程和模块2.添加 web支持3.创建前端代码4.添加servlet 依赖5. 代码6.案例2 1.创建工程和模块 2.添加 web支持 方法1 方法2 3.创建前端代码 4.添加servlet 依赖 5. 代码 <!DOCTYPE html> <html lang"en"> <head><meta c…

被斯坦福抄作业了?在线体验下:国产大模型确实越来越棒啦!

抄袭&#xff1f; 这里不做评价了&#xff1a; 官方仓库 地址&#xff1a;miniCPM-Llama3-V-2_5 免费在线体验地址 链接&#xff1a;Llama3-V-2_5 模型能力&#xff1a; 模型实际体验 问他什么模型&#xff1a;&#xff08;可能用了它的数据集吧&#xff09; 图片分析…

星创编辑器在投放业务中的落地|得物技术

搭建一个落地页需要涉及到多方合作&#xff0c;需要不断地进行沟通协调。繁杂的流程需要耗费很多的时间&#xff0c;因此我们推动产品重新搭建了一个专门服务于软广投放流程的编辑器——星创&#xff0c;完成广告搭建在投放业务各系统中的闭环。 一、落地页技术架构 名词解释…

数据新生态:Web3如何重新定义个人数据权利

随着数字化时代的不断深入&#xff0c;个人数据已经成为了现代社会中最宝贵的资源之一。然而&#xff0c;传统互联网时代下&#xff0c;个人数据往往被大型科技公司垄断、滥用&#xff0c;个人数据权利常常受到侵犯。而随着Web3技术的崛起&#xff0c;人们开始期待一种全新的数…

这几年一直有人在问:软件行业现在环境好不好?(俩张图告诉你答案)IT还有机会回暖吗?

这几年一直有人在问:软件行业现在环境好不好?(俩张图告诉你答案)IT还有机会回暖吗? 近几年软件行业确实是不太景气,身边很多朋友都面临找工作难的景象.it培训行业也是对老师进行裁员,砍掉大部分学科, 大家可以在下方评论发表自己的看法,认为IT还有机会回暖吗?

Vue进阶之Vue无代码可视化项目(四)

Vue无代码可视化项目 左侧栏第一步LeftPanel.vueLayoutView.vuebase.css第二步LayoutView.vueLeftPanel.vue编排引擎smooth-dnd安装创建文件SmoothDndContainer.tsutils.tsSmoothDndDraggable.tsLeftPanel.vue左侧栏 第一步 创建LeftPanel LeftPanel.vue <script setup…

第15章 面向服务架构设计理论实践

服务是一个由服务提供者提供的&#xff0c;用于满足使用者请求的业务单元。服务的提供者和使用者都是软件代理为了各自的利益而产生的角色。 在面向服务的体系结构(Service-Oriented Architecture,SOA)中&#xff0c;服务的概念有了延伸&#xff0c;泛指系统对外提供的功能集。…

Python文档生成工具库之alabaster使用详解

概要 在编写文档时,美观和易读性是两个重要的方面。Sphinx 是一个广泛使用的文档生成工具,而 Alabaster 是 Sphinx 默认的主题。alabaster 主题以其简洁优雅的设计和易用的配置选项受到广大用户的欢迎。本文将详细介绍 alabaster 库,包括其安装方法、主要特性、基本和高级功…

php质量工具系列之PHPCPD

PHPCPD 用于检测重复代码&#xff0c;直观的说就是复制粘贴再稍微改改 该工具作者已经 停止维护 安装 composer global require --dev sebastian/phpcpd执行 phpcpd --log-pmd phpcpd_result.xml ./app参数介绍 --log-pmd 将结果保存在phpcpd_result.xml 中 ./app 是phpcpd扫…

【传知代码】偏标记学习+图像分类(论文复现)

前言&#xff1a;偏标记学习&#xff0c;顾名思义&#xff0c;就是在训练数据集中&#xff0c;每个样本的标签不是完全确定的&#xff0c;而是由多个可能的标签组成的集合。这种学习范式更加贴近现实世界的场景&#xff0c;因为在很多情况下&#xff0c;我们无法为图像提供精确…

可的哥(Codigger)推出Monaco编辑器插件,提升编程体验

Monaco编辑器&#xff0c;作为业界领先的代码编辑器&#xff0c;在编程体验中发挥着不可或缺的重要作用&#xff0c;能够在多种编程语言和开发环境中表现出色&#xff0c;为开发者提供高效、便捷的编程环境。可的哥&#xff08;Codigger&#xff09;在应用商店上线Monaco编辑器…

在618集中上新,蕉下、VVC们为何押注拼多多?

编辑&#xff5c;Ray 自前两年崛起的防晒产品&#xff0c;今年依旧热度不减。 头部品牌蕉下&#xff0c;2020年入驻拼多多&#xff0c;如今年销售额已过亿元。而自去年起重点押注拼多多的时尚防晒品牌VVC&#xff0c;很快销量翻番。这两家公司&#xff0c;不约而同在618之前上…

设备巡检系统是如何实现一次操作闭环管理的

设备巡检系统通过一系列功能设计&#xff0c;实现了从任务分配到问题处理的一次操作闭环管理。以下是具体的实现方式&#xff1a; 一、多类型任务无感操作 任务识别与整合&#xff1a;系统能够自动识别各种巡检、重大危险源排查及现场检修等任务的类型和优先级&#xff0c;并…

企业全面管理解决方案:基于Java技术的ERP管理系统源码

功能模块与描述&#xff1a; ERP首页&#xff1a; 销售统计与采购统计&#xff1a;实时展示销售和采购金额的统计数据。折线图统计&#xff1a;通过图表直观展示销售和采购趋势。 采购管理&#xff1a; 采购订单管理&#xff1a;处理采购订单的搜索、新增、导出等。采购入库与退…