YangYuchen
软件体系结构期末复习(一)

软件体系结构期末复习(一)

此文章仅用作期末复习

一、DomainModel

Domain model是指对系统的领域(domain)进行抽象化和建模,以便于更好地理解和描述该领域的实体、属性和行为。它通常是由一系列的类、属性和方法组成,用于描述业务领域的对象以及它们之间的关系和行为。
一般来说,domain model可以通过UML(统一建模语言)类图或者ER(实体关系)图来进行表示。其中,UML类图主要用来表示类之间的关系和属性。
而ER图则主要用来表示实体之间的关系。

需要注意的是,domain model并不是一个完整的系统架构,而是一个高抽象度的模型,用于描述业务领域中的实体、属性和行为。在实现具体的系统时,需要进一步细化这些抽象模型,为每个实体建立具体的实现类,以及对它们之间的关系进行实际的编码。

补充

  • DomainModel:用户对其用户的构建与预期,用特定领域的术语表示。描述业务核心(最有价值且可能发生变化)。
  • 构建目的:保持模型与基础设施的分离。即Persistence ignorance(持久性忽略)。
  • 值对象Value Objects :由它所持有的数据唯一标识(而不是由ID)。
  • 实体Entities:对于具有永久ID(由引用标识)的东西。例如,一个人(具有永久身份的人)
  • 域服务Domain Service:操作,服务与功能。
  • 业务逻辑Business Logic:领域模型包括业务逻辑。

二、Persistence ignorance(持久性忽略)

Persistence Ignorance是指应用程序的核心领域(domain)层不应该依赖于数据持久化层的技术细节,也就是说,领域层应该是独立于基础设施层的。这种设计模式的目的是增强系统的可维护性,降低系统的耦合度,并提高系统的灵活性和可扩展性。

具体来说,persistence ignorance要求领域层的对象和方法不依赖于任何特定的数据持久化技术,如ORM框架、SQL语句等。而是在应用程序中定义领域对象和方法,而数据持久化则可以采用各种技术实现,如关系数据库、NoSQL数据库、文件、缓存等。这样,当需要更改或替换数据持久化技术时,领域层的代码不需要做任何修改,只需更改基础设施层的实现即可。

实现persistence ignorance有助于将关注点分离(Separation of Concerns),即将不同的职责分配给不同的模块或组件。这样,业务逻辑和数据持久化逻辑都可以单独维护和测试。同时,这也使得应用程序更加易于扩展和升级,因为应用程序的核心逻辑不会因为更改基础设施层的技术而受到影响。

然而,需要注意的是,严格遵循persistence ignorance不一定是最好的选择。在某些情况下,领域层需要访问数据持久化层的某些细节,如特定的查询、缓存、事务控制等。这种情况下,可以通过使用repository模式等技术来实现数据访问的抽象化,以保证领域层的独立性。

三、Repository Patterns仓库模式

Repository模式是一种常用的设计模式,它是一种数据访问层的抽象,将数据访问的逻辑和业务逻辑分离,使得业务逻辑更加清晰,同时可以方便地进行单元测试。

Repository模式的核心思想是将数据访问的实现细节从业务逻辑中隔离开来,把数据访问的行为封装在一个仓库中,对外提供简单、明确的接口,使得客户端可以更加方便地访问数据。

以下是一个简单的C#代码演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public interface IRepository<TEntity> where TEntity : class
{
TEntity GetById(int id);
IEnumerable<TEntity> GetAll();
void Add(TEntity entity);
void Update(TEntity entity);
void Delete(TEntity entity);
}

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly DbContext _dbContext;

public Repository(DbContext dbContext)
{
_dbContext = dbContext;
}

public TEntity GetById(int id)
{
return _dbContext.Set<TEntity>().Find(id);
}

public IEnumerable<TEntity> GetAll()
{
return _dbContext.Set<TEntity>().ToList();
}

public void Add(TEntity entity)
{
_dbContext.Set<TEntity>().Add(entity);
}

public void Update(TEntity entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
}

public void Delete(TEntity entity)
{
_dbContext.Set<TEntity>().Remove(entity);
}
}

// 使用示例
public class UserService
{
private readonly IRepository<User> _userRepository;

public UserService(IRepository<User> userRepository)
{
_userRepository = userRepository;
}

public void CreateUser(User user)
{
// TODO: 业务逻辑处理
_userRepository.Add(user);
}

public User GetUserById(int id)
{
// TODO: 业务逻辑处理
return _userRepository.GetById(id);
}

// 其他方法省略
}

在上面的代码中,IRepository接口定义了一些基本的数据访问操作,包括获取实体、获取所有实体、添加实体、更新实体和删除实体等。Repository类实现了这些基本的操作,具体的数据库访问实现由EF Core提供。UserService类通过依赖注入方式使用IRepository<User>,并在业务逻辑中调用相应的方法进行数据访问。

下面我们用Python代码来演示另一个简单的Repository模式实现。首先,我们定义一个接口类,它包含了一些标准方法用于访问数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from abc import ABC, abstractmethod
from typing import List

class Repository(ABC):
@abstractmethod
def add(self, entity):
pass

@abstractmethod
def update(self, entity):
pass

@abstractmethod
def delete(self, entity):
pass

@abstractmethod
def get_all(self) -> List:
pass

@abstractmethod
def get_by_id(self, id) -> object:
pass

接下来,我们定义一个具体的实现类,该类使用Python内置的字典作为数据存储方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class DictRepository(Repository):
def __init__(self):
self.data = {}
self.id = 0

def add(self, entity):
self.id += 1
entity.id = self.id
self.data[self.id] = entity

def update(self, entity):
self.data[entity.id] = entity

def delete(self, entity):
if entity.id in self.data:
del self.data[entity.id]

def get_all(self) -> List:
return list(self.data.values())

def get_by_id(self, id) -> object:
return self.data.get(id)

最后,我们定义一个实体类作为数据的一个样例,用于演示Repository模式的使用:

1
2
3
4
5
6
7
8
class User:
def __init__(self, name, age):
self.id = None
self.name = name
self.age = age

def __str__(self):
return f"{self.id}: {self.name} ({self.age})"

现在,我们可以使用DictRepository实现类来访问数据了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
repo = DictRepository()

# 添加一个实体
user1 = User("Alice", 25)
repo.add(user1)

# 获取所有实体
print(repo.get_all())

# 添加更多实体
user2 = User("Bob", 30)
repo.add(user2)
user3 = User("Charlie", 35)
repo.add(user3)

# 更新一个实体
user2.age = 40
repo.update(user2)

# 删除一个实体
repo.delete(user3)

# 获取一个实体
print(repo.get_by_id(2))

输出结果为:

1
2
3
4
5
[1: Alice (25)]
[1: Alice (25), 2: Bob (30), 3: Charlie (35)]
[1: Alice (25), 2: Bob (40), 3: Charlie (35)]
[1: Alice (25), 2: Bob (40)]
Bob (40)

我们可以看到,使用Repository模式可以使数据访问更加独立和模块化,并且易于扩展和维护。
通过这种方式,数据访问逻辑和业务逻辑得到了有效地分离,使得代码更加清晰、易于维护和测试。

四、Service Layer Pattern服务层模式

Service Layer Pattern,即服务层模式,是一种常用的软件架构设计模式。它将应用程序划分成三个层次:表示层、服务层和数据访问层。表示层处理用户与应用程序之间的交互,数据访问层负责与数据库或其他数据存储源交互,并且服务层作为中间层,提供一组功能,以便表示层可以调用它们来获取所需的数据和进行逻辑处理。这种模式具有良好的模块化和可扩展性,使得应用程序更易于维护和升级。

以下是Python实现的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 数据访问层
class UserDao:
def __init__(self, db):
self.db = db

def get_user(self, user_id):
# 从数据库获取用户
...

def save_user(self, user):
# 将用户保存到数据库
...

# 服务层
class UserService:
def __init__(self, dao):
self.dao = dao

def get_user(self, user_id):
user = self.dao.get_user(user_id)
# 在此添加必要的业务逻辑
return user

def save_user(self, user):
# 在此添加必要的业务逻辑
self.dao.save_user(user)

# 表示层
class UserController:
def __init__(self, service):
self.service = service

def get_user(self, user_id):
user = self.service.get_user(user_id)
# 在此添加渲染用户信息的代码
...

def save_user(self, user):
# 在此添加处理用户提交的表单数据的代码
self.service.save_user(user)

# 创建对象并使用
db = Database("localhost", "user", "password")
dao = UserDao(db)
service = UserService(dao)
controller = UserController(service)
controller.get_user(1)
controller.save_user(user)

以上示例中,Python代码中的三个层次分别是:表示层(UserController类)、服务层(UserService类)和数据访问层(UserDao类)。UserController类接收用户的请求并将其传递给服务层;UserService类封装了对数据访问层的调用,并在必要时处理业务逻辑;UserDao类与数据库交互,获取或保存用户数据。三个层次之间通过依赖注入的方式进行联系,使得它们能够独立测试和修改。

五、Unit of work Pattern工作单元模式

Unit of work pattern 是一种软件设计模式,用于跟踪在一个事务内的所有更改,并将这些更改一起提交或回滚。

在这个模式中,一个工作单元代表了一个事务,可以跟踪修改的对象和操作,直到事务被提交或回滚。这可以确保数据一致性和事务的原子性。

下面是一个简单的Python代码示例,用于演示如何实现 Unit of work pattern:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class UnitOfWork:
def __init__(self):
self.new_objects = []
self.dirty_objects = []
self.removed_objects = []

def register_new(self, obj):
self.new_objects.append(obj)

def register_dirty(self, obj):
self.dirty_objects.append(obj)

def register_removed(self, obj):
self.removed_objects.append(obj)

def commit(self):
# 将所有新建的对象插入数据库
for obj in self.new_objects:
insert(obj)
# 将所有修改过的对象更新到数据库
for obj in self.dirty_objects:
update(obj)
# 将所有被删除的对象从数据库中删除
for obj in self.removed_objects:
delete(obj)

在这个示例中,我们定义了一个 UnitOfWork 类,其中包括三个列表,用于跟踪新建、修改和删除的对象。register_new、register_dirty 和 register_removed 方法用于将对象添加到相应的列表中。commit 方法将在一个事务中将所有更改提交到数据库中。

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建 UnitOfWork 对象
uow = UnitOfWork()

# 创建新对象
p1 = Person("Alice", 25)
p2 = Person("Bob", 30)

# 将新对象注册到 UnitOfWork
uow.register_new(p1)
uow.register_new(p2)

# 修改对象
p1.age += 1
uow.register_dirty(p1)

# 删除对象
uow.register_removed(p2)

# 提交所有更改
uow.commit()

在这个示例中,我们创建了两个新 Person 对象,将它们注册到 UnitOfWork 中。然后我们修改了一个对象并将其标记为已修改,将另一个对象标记为被删除。最后,我们提交了所有更改,这将把所有新建、修改和删除的对象保存到数据库中。

本文作者:YangYuchen
本文链接:https://www.littlewhite.site/软件体系结构复习-一/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可