面向对象设计映射与高效可扩展远程服务器技术解析
在软件开发领域,面向对象设计的映射以及远程服务器的高效可扩展性是两个重要的研究方向。下面将详细介绍相关的设计模式和技术。
面向对象设计映射到 Ada
在面向对象设计映射到 Ada 的过程中,我们定义了一些类型和过程,以实现客户相关的功能。以下是相关代码:
type Customer_Type is new Person_Type with private;
type Customer_Ref is access all Customer_Type'Class;
procedure Open_Checking
(Customer: in Customer_Ref; Checking: in Checking_Ref);
-- Will check that Checking.Owner = Customer_Ref.
-- If needed, we can enforce that Open_Checking is
-- called only once for a given Customer.
function Checking_Account_Of
(Customer: Customer_Type) return Checking_Ref;
-- Open_Savings and Savings_Account_Of are similar, and omitted.
procedure File
(Customer: in out Customer_Type;
Transaction: in Transaction_Ref) ;
private
type Controlled_Checking_Ref is new Controlled with
record
Reference: Checking_Ref;
end record;
procedure Finalize
(Checking_Ref: in out Controlled_Checking_Ref);
-- will close the checking account hold by the customer.
-- Similar for Savings.
type Customer_Type is new Person_Type with record
Owned_Checking : Controlled_Checking_Ref;
Owned_Savings : Controlled_Savings_Ref;
Transactions: Transaction_Sets.Set_Type;
end record;
end Customers;
上述代码中,
Customer_Type
是从
Person_Type
派生而来的新类型,用于表示客户。
Open_Checking
过程用于为客户开设支票账户,同时会检查账户所有者是否匹配。
Checking_Account_Of
函数用于获取客户的支票账户引用。
File
过程用于处理客户的交易记录。
在
private
部分,定义了
Controlled_Checking_Ref
类型,用于控制支票账户的引用。
Finalize
过程用于关闭客户持有的支票账户。
Fusion 方法的改进
Fusion 方法在使用过程中存在一些问题,我们对其进行了改进:
-
术语使用
:Fusion 使用“对象模型”,我们更倾向于“类模型”。
-
动态可见性
:Fusion 通常忽略动态可见性,且未意识到它暗示了类之间的依赖关系。我们提出简化规则,即永久可见性使动态可见性冗余。
-
抽象类
:Fusion 在类描述中不考虑抽象类。当子类划分父类时,父类应声明为抽象类;当方法只能为子类定义时,该方法应在父类中声明为抽象方法。例如,
Withdraw
方法只有在知道账户类型时才能定义,因为支票账户和储蓄账户的规则不同。
-
局部方法
:如果一个方法从未从外部调用,我们建议将其标记为局部方法,如
Account
的
Withdraw
和
Deposit
方法。
与其他作者工作的比较
不同作者在相关领域提出了不同的观点和方法:
-
消息传递描绘
:我们受 Kris Oosting 的启发,提出了如何描绘集合的消息传递。但我们认为在设计对象交互图时过早决定具体的数据结构是不成熟的,只有完整的对象交互图集合才能显示给定集合所需的方法。
-
可见性图
:Martin van Amersfoorth 建议在可见性图中显示链接是相互反向的,设计和实现可以利用此信息保证引用完整性。
-
命名问题
:Rosen 广泛讨论了 Ada 的命名问题,他解释了我们在本文中使用的后缀表示法,但他更倾向于通用标识符,这在多个类型直接可见时会导致困难。
高效可扩展多线程远程服务器
在远程服务器的设计中,服务器通常需要对客户端施加调用协议,同时处理多个客户端请求。为了解决这些问题,我们引入了两种设计模式:MT - Rendezvous 和 CompositeCalls。
MT - Rendezvous 设计模式
MT - Rendezvous 设计模式支持多线程会合,每个客户端由不同的服务器线程服务。其调用流程如下:
1. 客户端将调用封装在
Call
类层次结构中,并发送请求。
2. 服务器端的
Forwarder
接收请求,检查是否有该客户端的服务器线程。如果没有,则创建一个。
3. 新创建的服务器线程用于与该客户端的会话。
4.
CourierTasks
用于异步执行实际调用,避免阻塞
Forwarder
。
调用路径如下表所示:
|步骤|操作|
|----|----|
|1|客户端向客户端存根发出请求|
|2|客户端存根扁平化调用并使用通信对象提交|
|3|扁平化的调用穿越网络|
|4|服务器存根从通信对象获取调用并解扁平化|
|5|转发器从本地存根获取调用。如果没有该客户端的服务器线程,则创建一个|
|6|转发器创建一个信使任务以异步进行调用|
|7|信使任务进行调用,服务器线程接受调用|
结果返回路径如下:
1. 信使任务和服务器线程的会合结束。
2. 信使任务将调用结果发送回本地存根。
3. 结果从服务器存根返回给客户端。
mermaid 流程图如下:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([客户端请求]):::startend --> B(客户端存根扁平化调用):::process
B --> C(调用穿越网络):::process
C --> D(服务器存根解扁平化调用):::process
D --> E{是否有服务器线程?}:::decision
E -->|否| F(创建服务器线程):::process
E -->|是| G(使用现有服务器线程):::process
F --> H(信使任务异步调用):::process
G --> H
H --> I(服务器线程接受调用):::process
I --> J(会合结束):::process
J --> K(信使任务返回结果):::process
K --> L(结果返回客户端):::process
CompositeCalls 设计模式
CompositeCalls 设计模式旨在减少跨域调用的数量,并提供服务器的动态扩展。客户端将与服务器交互的代码封装在一个对象中,提交给服务器。服务器端对其进行解释,使本地过程调用就足够了。
该模式的特点如下:
-
程序类型
:客户端代码被称为程序(也称为复合调用),可以使用不同的语言构建。每种程序由一种命令组成,如高级程序由高级命令组成,低级程序由低级命令组成。
-
变量表
:使用
VarTable
来保存程序状态,以及程序的输入和输出参数。变量被标记为
In
、
Out
、
InOut
或
None
模式。
-
服务器调用
:对于每个服务器,命令层次结构通过服务器提供的服务集进行扩展,称为
ServerCalls
。
ServerCalls
的参数值在提交时未知,而是在解释时确定。
调用流程如下:
1. 客户端创建
ServerCall
,并将需要作为参数的变量传递给构造函数。
2. 客户端将调用提交给服务器。
3. 服务器调用程序的
Run
方法,
Run
方法调用涉及的命令的
Do
方法。
mermaid 流程图如下:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([客户端创建 ServerCall]):::startend --> B(客户端提交调用):::process
B --> C(服务器接收调用):::process
C --> D(服务器调用 Run 方法):::process
D --> E(调用命令的 Do 方法):::process
E --> F(执行命令):::process
F --> G(返回结果给客户端):::process
通过结合 MT - Rendezvous 和 CompositeCalls 模式,可以实现高效、可扩展和表达性强的多线程服务器。在下半部分,我们将详细介绍如何将这两种模式结合,以及在实际应用中的具体案例。
面向对象设计映射与高效可扩展远程服务器技术解析
结合 MT - Rendezvous 和 CompositeCalls 模式
将 MT - Rendezvous 和 CompositeCalls 模式结合起来,可以创建高效、可扩展且表达性强的多线程服务器。不过,这两种模式存在一些差异,需要进行合理的整合。
两种模式的差异
- 调用处理方式 :在 MT - Rendezvous 模式中,调用封装了实际参数和要调用的服务;而在 CompositeCalls 模式中,实际参数在客户端未知,而是在服务器解释程序时确定。
- 服务器结构 :CompositeCalls 模式下的服务器结构可以很简单,只需一个接收程序并执行的线程;MT - Rendezvous 模式则有更复杂的框架,需要处理多个服务器线程和请求转发策略。
整合指南
为了顺利整合这两种模式,我们制定了以下指南:
-
统一调用类层次结构
:将 MT - Rendezvous 的抽象
Call
作为 CompositeCalls 抽象
Command
的子类,避免冗余和冲突。
-
保留灵活性
:确保封装的转发策略、使用不同语言/解释器的能力、为新服务器重用现有语言/解释器的能力以及对并发客户端的支持不受影响。
-
支持多种调用方式
:允许客户端提交单个调用和复合调用。
构建 CompositeRendezvousCalls 设计模式
按照上述整合指南,我们可以构建 CompositeRendezvousCalls 设计模式。具体步骤如下:
1.
统一调用类层次结构
:将 MT - Rendezvous 的
Call
类作为 CompositeCalls 的
Command
类的子类。
2.
保留功能
:确保转发策略、语言/解释器的使用等功能不受影响。
3.
支持多种调用
:客户端可以提交单个调用或复合调用。
调用流程如下表所示:
|步骤|操作|
|----|----|
|1|客户端提交复合调用或程序到服务器|
|2|服务器检查是否有与客户端关联的服务器任务。如果没有,则创建一个|
|3|服务器解释程序,将调用本地发送到关联的服务器任务|
|4|程序执行完成后,结果返回给客户端|
mermaid 流程图如下:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([客户端提交复合调用]):::startend --> B{是否有服务器任务?}:::decision
B -->|否| C(创建服务器任务):::process
B -->|是| D(使用现有服务器任务):::process
C --> E(服务器解释程序):::process
D --> E
E --> F(本地调用服务器任务):::process
F --> G(程序执行完成):::process
G --> H(返回结果给客户端):::process
实际应用案例
CompositeRendezvousCalls 设计模式在多个领域有实际应用,下面介绍一个分布式 Ada 应用的事务框架 TransLib。
TransLib 事务框架
TransLib 是一个用于分布式 Ada 应用的事务框架,它利用了 CompositeRendezvousCalls 设计模式的优势。具体应用如下:
-
简化服务器设计
:服务器只需包含基本服务,通过复合调用可以动态扩展功能。
-
清晰的交互结构
:利用会合的表达能力,使客户端和服务器的交互更加清晰。
-
高效的交互
:复合调用中的所有服务器调用都不穿越网络,提高了交互效率。
-
易于编写的服务器代码
:服务器代码只需处理单个客户端,同时通过多线程可以并行服务不同客户端,提高吞吐量。
-
单一调用表达完整会话
:可以将会合强制的调用协议中的各个步骤组合成一个单一的调用。
相关设计模式
除了 MT - Rendezvous 和 CompositeCalls 模式,还有一些相关的设计模式值得关注:
-
RPC 模型
:与会合机制相比,RPC 模型在强制客户端调用协议方面较为困难,需要记录调用结果、测试结果并维护共享数据结构。
-
传统会合模型
:传统会合模型中,单个服务器线程处理所有客户端,难以实现多线程服务器和不同客户端的不同调用协议。
总结
通过对面向对象设计映射到 Ada 的介绍,以及对 MT - Rendezvous 和 CompositeCalls 设计模式的分析,我们了解到如何构建高效、可扩展和表达性强的多线程远程服务器。将这两种模式结合起来的 CompositeRendezvousCalls 设计模式,在分布式应用中具有明显的优势,如简化服务器设计、提高交互效率、增强表达能力等。在实际应用中,我们可以根据具体需求选择合适的设计模式,以实现最佳的性能和可扩展性。
在软件开发过程中,不断探索和应用新的设计模式和技术,有助于提高软件的质量和效率,满足日益增长的业务需求。希望本文介绍的内容能为开发者在设计和实现远程服务器时提供有益的参考。