Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
QZero_0
java-design-patterns
提交
2823166c
J
java-design-patterns
项目概览
QZero_0
/
java-design-patterns
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
java-design-patterns
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
2823166c
编写于
1月 01, 2022
作者:
I
Ilkka Seppälä
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor unit of work
上级
2679f7aa
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
204 addition
and
200 deletion
+204
-200
unit-of-work/README.md
unit-of-work/README.md
+109
-105
unit-of-work/etc/unit-of-work.ucls
unit-of-work/etc/unit-of-work.ucls
+3
-3
unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java
unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java
+13
-11
unit-of-work/src/main/java/com/iluwatar/unitofwork/ArmsDealer.java
...ork/src/main/java/com/iluwatar/unitofwork/ArmsDealer.java
+31
-31
unit-of-work/src/main/java/com/iluwatar/unitofwork/Weapon.java
...of-work/src/main/java/com/iluwatar/unitofwork/Weapon.java
+2
-4
unit-of-work/src/main/java/com/iluwatar/unitofwork/WeaponDatabase.java
...src/main/java/com/iluwatar/unitofwork/WeaponDatabase.java
+5
-5
unit-of-work/src/test/java/com/iluwatar/unitofwork/ArmsDealerTest.java
...src/test/java/com/iluwatar/unitofwork/ArmsDealerTest.java
+41
-41
未找到文件。
unit-of-work/README.md
浏览文件 @
2823166c
...
...
@@ -12,20 +12,20 @@ tags:
## Intent
When a business transaction is completed, all the
the
updates are sent as one big unit of work to be
When a business transaction is completed, all the updates are sent as one big unit of work to be
persisted in one go to minimize database round-trips.
## Explanation
Real
world example
Real
-
world example
>
We have a database containing student information. Administrators all over the country
are
> constantly updating this information and it causes high load on the database server. To make the
>
Arms dealer has a database containing weapon information. Merchants all over the town
are
> constantly updating this information and it causes
a
high load on the database server. To make the
> load more manageable we apply to Unit of Work pattern to send many small updates in batches.
In plain words
> Unit of Work merges many small database updates in single batch to optimize the number of
> Unit of Work merges many small database updates in
a
single batch to optimize the number of
> round-trips.
[
MartinFowler.com
](
https://martinfowler.com/eaaCatalog/unitOfWork.html
)
says
...
...
@@ -35,37 +35,20 @@ In plain words
**Programmatic Example**
Here's the
`
Student`
entity that is being persisted to
the database.
Here's the
`
Weapon`
entity that is being persisted in
the database.
```
java
public
class
Student
{
private
final
Integer
id
;
private
final
String
name
;
private
final
String
address
;
public
Student
(
Integer
id
,
String
name
,
String
address
)
{
this
.
id
=
id
;
this
.
name
=
name
;
this
.
address
=
address
;
}
public
String
getName
()
{
return
name
;
}
public
Integer
getId
()
{
return
id
;
}
public
String
getAddress
()
{
return
address
;
}
@Getter
@RequiredArgsConstructor
public
class
Weapon
{
private
final
Integer
id
;
private
final
String
name
;
}
```
The essence of the implementation is the
`
StudentRepository
`
implementing the Unit of Work pattern.
The essence of the implementation is the
`
ArmsDealer
`
implementing the Unit of Work pattern.
It maintains a map of database operations (
`context`
) that need to be done and when
`commit`
is
called it applies them in single batch.
called it applies them in
a
single batch.
```
java
public
interface
IUnitOfWork
<
T
>
{
...
...
@@ -84,96 +67,117 @@ public interface IUnitOfWork<T> {
}
@Slf4j
public
class
StudentRepository
implements
IUnitOfWork
<
Student
>
{
private
final
Map
<
String
,
List
<
Student
>>
context
;
private
final
StudentDatabase
studentDatabase
;
public
StudentRepository
(
Map
<
String
,
List
<
Student
>>
context
,
StudentDatabase
studentDatabase
)
{
this
.
context
=
context
;
this
.
studentDatabase
=
studentDatabase
;
}
@Override
public
void
registerNew
(
Student
student
)
{
LOGGER
.
info
(
"Registering {} for insert in context."
,
student
.
getName
());
register
(
student
,
IUnitOfWork
.
INSERT
);
}
@Override
public
void
registerModified
(
Student
student
)
{
LOGGER
.
info
(
"Registering {} for modify in context."
,
student
.
getName
());
register
(
student
,
IUnitOfWork
.
MODIFY
);
}
@Override
public
void
registerDeleted
(
Student
student
)
{
LOGGER
.
info
(
"Registering {} for delete in context."
,
student
.
getName
());
register
(
student
,
IUnitOfWork
.
DELETE
);
}
private
void
register
(
Student
student
,
String
operation
)
{
var
studentsToOperate
=
context
.
get
(
operation
);
if
(
studentsToOperate
==
null
)
{
studentsToOperate
=
new
ArrayList
<>();
@RequiredArgsConstructor
public
class
ArmsDealer
implements
IUnitOfWork
<
Weapon
>
{
private
final
Map
<
String
,
List
<
Weapon
>>
context
;
private
final
WeaponDatabase
weaponDatabase
;
@Override
public
void
registerNew
(
Weapon
weapon
)
{
LOGGER
.
info
(
"Registering {} for insert in context."
,
weapon
.
getName
());
register
(
weapon
,
UnitActions
.
INSERT
.
getActionValue
());
}
studentsToOperate
.
add
(
student
);
context
.
put
(
operation
,
studentsToOperate
);
}
@Override
public
void
commit
()
{
if
(
context
==
null
||
context
.
size
()
==
0
)
{
return
;
@Override
public
void
registerModified
(
Weapon
weapon
)
{
LOGGER
.
info
(
"Registering {} for modify in context."
,
weapon
.
getName
());
register
(
weapon
,
UnitActions
.
MODIFY
.
getActionValue
());
}
LOGGER
.
info
(
"Commit started"
);
if
(
context
.
containsKey
(
IUnitOfWork
.
INSERT
))
{
commitInsert
();
@Override
public
void
registerDeleted
(
Weapon
weapon
)
{
LOGGER
.
info
(
"Registering {} for delete in context."
,
weapon
.
getName
());
register
(
weapon
,
UnitActions
.
DELETE
.
getActionValue
());
}
if
(
context
.
containsKey
(
IUnitOfWork
.
MODIFY
))
{
commitModify
();
private
void
register
(
Weapon
weapon
,
String
operation
)
{
var
weaponsToOperate
=
context
.
get
(
operation
);
if
(
weaponsToOperate
==
null
)
{
weaponsToOperate
=
new
ArrayList
<>();
}
weaponsToOperate
.
add
(
weapon
);
context
.
put
(
operation
,
weaponsToOperate
);
}
if
(
context
.
containsKey
(
IUnitOfWork
.
DELETE
))
{
commitDelete
();
/**
* All UnitOfWork operations are batched and executed together on commit only.
*/
@Override
public
void
commit
()
{
if
(
context
==
null
||
context
.
size
()
==
0
)
{
return
;
}
LOGGER
.
info
(
"Commit started"
);
if
(
context
.
containsKey
(
UnitActions
.
INSERT
.
getActionValue
()))
{
commitInsert
();
}
if
(
context
.
containsKey
(
UnitActions
.
MODIFY
.
getActionValue
()))
{
commitModify
();
}
if
(
context
.
containsKey
(
UnitActions
.
DELETE
.
getActionValue
()))
{
commitDelete
();
}
LOGGER
.
info
(
"Commit finished."
);
}
LOGGER
.
info
(
"Commit finished."
);
}
private
void
commitInsert
()
{
var
studentsToBeInserted
=
context
.
get
(
IUnitOfWork
.
INSERT
);
for
(
var
student
:
studentsToBeInserted
)
{
LOGGER
.
info
(
"Saving {} to database."
,
student
.
getName
());
studentDatabase
.
insert
(
student
);
private
void
commitInsert
()
{
var
weaponsToBeInserted
=
context
.
get
(
UnitActions
.
INSERT
.
getActionValue
());
for
(
var
weapon
:
weaponsToBeInserted
)
{
LOGGER
.
info
(
"Inserting a new weapon {} to sales rack."
,
weapon
.
getName
());
weaponDatabase
.
insert
(
weapon
);
}
}
}
private
void
commitModify
()
{
var
modifiedStudents
=
context
.
get
(
IUnitOfWork
.
MODIFY
);
for
(
var
student
:
modifiedStudents
)
{
LOGGER
.
info
(
"Modifying {} to database."
,
student
.
getName
());
studentDatabase
.
modify
(
student
);
private
void
commitModify
()
{
var
modifiedWeapons
=
context
.
get
(
UnitActions
.
MODIFY
.
getActionValue
());
for
(
var
weapon
:
modifiedWeapons
)
{
LOGGER
.
info
(
"Scheduling {} for modification work."
,
weapon
.
getName
());
weaponDatabase
.
modify
(
weapon
);
}
}
}
private
void
commitDelete
()
{
var
deletedStudents
=
context
.
get
(
IUnitOfWork
.
DELETE
);
for
(
var
student
:
deletedStudents
)
{
LOGGER
.
info
(
"Deleting {} to database."
,
student
.
getName
());
studentDatabase
.
delete
(
student
);
private
void
commitDelete
()
{
var
deletedWeapons
=
context
.
get
(
UnitActions
.
DELETE
.
getActionValue
());
for
(
var
weapon
:
deletedWeapons
)
{
LOGGER
.
info
(
"Scrapping {}."
,
weapon
.
getName
());
weaponDatabase
.
delete
(
weapon
);
}
}
}
}
```
Finally, here's how we use the
`StudentRepository`
and
`commit`
the transaction
.
Here is how the whole app is put together
.
```
java
studentRepository
.
registerNew
(
ram
);
studentRepository
.
registerModified
(
shyam
);
studentRepository
.
registerDeleted
(
gopi
);
studentRepository
.
commit
();
// create some weapons
var
enchantedHammer
=
new
Weapon
(
1
,
"enchanted hammer"
);
var
brokenGreatSword
=
new
Weapon
(
2
,
"broken great sword"
);
var
silverTrident
=
new
Weapon
(
3
,
"silver trident"
);
// create repository
var
weaponRepository
=
new
ArmsDealer
(
new
HashMap
<
String
,
List
<
Weapon
>>(),
new
WeaponDatabase
());
// perform operations on the weapons
weaponRepository
.
registerNew
(
enchantedHammer
);
weaponRepository
.
registerModified
(
silverTrident
);
weaponRepository
.
registerDeleted
(
brokenGreatSword
);
weaponRepository
.
commit
();
```
Here is the console output.
```
21:39:21.984 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Registering enchanted hammer for insert in context.
21:39:21.989 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Registering silver trident for modify in context.
21:39:21.989 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Registering broken great sword for delete in context.
21:39:21.989 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Commit started
21:39:21.989 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Inserting a new weapon enchanted hammer to sales rack.
21:39:21.989 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Scheduling silver trident for modification work.
21:39:21.989 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Scrapping broken great sword.
21:39:21.989 [main] INFO com.iluwatar.unitofwork.ArmsDealer - Commit finished.
```
## Class diagram
...
...
@@ -186,7 +190,7 @@ Use the Unit Of Work pattern when
*
To optimize the time taken for database transactions.
*
To send changes to database as a unit of work which ensures atomicity of the transaction.
*
To reduce number of database calls.
*
To reduce
the
number of database calls.
## Tutorials
...
...
unit-of-work/etc/unit-of-work.ucls
浏览文件 @
2823166c
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram
version=
"1.2.1"
icons=
"true"
always-add-relationships=
"false"
generalizations=
"true"
realizations=
"true"
associations=
"true"
dependencies=
"false"
nesting-relationships=
"true"
router=
"FAN"
>
<class
id=
"1"
language=
"java"
name=
"com.iluwatar.unitofwork.
StudentDatabase"
project=
"unit-of-work"
<class
id=
"1"
language=
"java"
name=
"com.iluwatar.unitofwork.
WeaponDatabase"
project=
"unit-of-work"
file=
"/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentDatabase.java"
binary=
"false"
corner=
"BOTTOM_RIGHT"
>
<position
height=
"-1"
width=
"-1"
x=
"170"
y=
"406"
/>
<display
autosize=
"true"
stereotype=
"true"
package=
"true"
initial-value=
"false"
signature=
"true"
...
...
@@ -28,7 +28,7 @@
<operations
public=
"true"
package=
"true"
protected=
"true"
private=
"true"
static=
"true"
/>
</display>
</class>
<class
id=
"4"
language=
"java"
name=
"com.iluwatar.unitofwork.
StudentRepository"
project=
"unit-of-work"
<class
id=
"4"
language=
"java"
name=
"com.iluwatar.unitofwork.
ArmsDealer"
project=
"unit-of-work"
file=
"/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java"
binary=
"false"
corner=
"BOTTOM_RIGHT"
>
<position
height=
"-1"
width=
"-1"
x=
"377"
y=
"166"
/>
...
...
@@ -38,7 +38,7 @@
<operations
public=
"true"
package=
"true"
protected=
"true"
private=
"true"
static=
"true"
/>
</display>
</class>
<class
id=
"5"
language=
"java"
name=
"com.iluwatar.unitofwork.
Student"
project=
"unit-of-work"
<class
id=
"5"
language=
"java"
name=
"com.iluwatar.unitofwork.
Weapon"
project=
"unit-of-work"
file=
"/unit-of-work/src/main/java/com/iluwatar/unitofwork/Student.java"
binary=
"false"
corner=
"BOTTOM_RIGHT"
>
<position
height=
"-1"
width=
"-1"
x=
"696"
y=
"130"
/>
<display
autosize=
"true"
stereotype=
"true"
package=
"true"
initial-value=
"false"
signature=
"true"
...
...
unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java
浏览文件 @
2823166c
...
...
@@ -27,7 +27,7 @@ import java.util.HashMap;
import
java.util.List
;
/**
* {@link App} Application
for managing student data
.
* {@link App} Application
demonstrating unit of work pattern
.
*/
public
class
App
{
/**
...
...
@@ -37,17 +37,19 @@ public class App {
*/
public
static
void
main
(
String
[]
args
)
{
var
ram
=
new
Student
(
1
,
"Ram"
,
"Street 9, Cupertino"
);
var
shyam
=
new
Student
(
2
,
"Shyam"
,
"Z bridge, Pune"
);
var
gopi
=
new
Student
(
3
,
"Gopi"
,
"Street 10, Mumbai"
);
// create some weapons
var
enchantedHammer
=
new
Weapon
(
1
,
"enchanted hammer"
);
var
brokenGreatSword
=
new
Weapon
(
2
,
"broken great sword"
);
var
silverTrident
=
new
Weapon
(
3
,
"silver trident"
);
var
context
=
new
HashMap
<
String
,
List
<
Student
>>();
var
studentDatabase
=
new
StudentDatabase
();
var
studentRepository
=
new
StudentRepository
(
context
,
studentDatabase
);
// create repository
var
weaponRepository
=
new
ArmsDealer
(
new
HashMap
<
String
,
List
<
Weapon
>>(),
new
WeaponDatabase
()
);
studentRepository
.
registerNew
(
ram
);
studentRepository
.
registerModified
(
shyam
);
studentRepository
.
registerDeleted
(
gopi
);
studentRepository
.
commit
();
// perform operations on the weapons
weaponRepository
.
registerNew
(
enchantedHammer
);
weaponRepository
.
registerModified
(
silverTrident
);
weaponRepository
.
registerDeleted
(
brokenGreatSword
);
weaponRepository
.
commit
();
}
}
unit-of-work/src/main/java/com/iluwatar/unitofwork/
StudentRepository
.java
→
unit-of-work/src/main/java/com/iluwatar/unitofwork/
ArmsDealer
.java
浏览文件 @
2823166c
...
...
@@ -30,41 +30,41 @@ import lombok.RequiredArgsConstructor;
import
lombok.extern.slf4j.Slf4j
;
/**
* {@link
StudentRepository} Student database repository. supports unit of work for student data
.
* {@link
ArmsDealer} Weapon repository that supports unit of work for weapons
.
*/
@Slf4j
@RequiredArgsConstructor
public
class
StudentRepository
implements
IUnitOfWork
<
Student
>
{
public
class
ArmsDealer
implements
IUnitOfWork
<
Weapon
>
{
private
final
Map
<
String
,
List
<
Student
>>
context
;
private
final
StudentDatabase
student
Database
;
private
final
Map
<
String
,
List
<
Weapon
>>
context
;
private
final
WeaponDatabase
weapon
Database
;
@Override
public
void
registerNew
(
Student
student
)
{
LOGGER
.
info
(
"Registering {} for insert in context."
,
student
.
getName
());
register
(
student
,
UnitActions
.
INSERT
.
getActionValue
());
public
void
registerNew
(
Weapon
weapon
)
{
LOGGER
.
info
(
"Registering {} for insert in context."
,
weapon
.
getName
());
register
(
weapon
,
UnitActions
.
INSERT
.
getActionValue
());
}
@Override
public
void
registerModified
(
Student
student
)
{
LOGGER
.
info
(
"Registering {} for modify in context."
,
student
.
getName
());
register
(
student
,
UnitActions
.
MODIFY
.
getActionValue
());
public
void
registerModified
(
Weapon
weapon
)
{
LOGGER
.
info
(
"Registering {} for modify in context."
,
weapon
.
getName
());
register
(
weapon
,
UnitActions
.
MODIFY
.
getActionValue
());
}
@Override
public
void
registerDeleted
(
Student
student
)
{
LOGGER
.
info
(
"Registering {} for delete in context."
,
student
.
getName
());
register
(
student
,
UnitActions
.
DELETE
.
getActionValue
());
public
void
registerDeleted
(
Weapon
weapon
)
{
LOGGER
.
info
(
"Registering {} for delete in context."
,
weapon
.
getName
());
register
(
weapon
,
UnitActions
.
DELETE
.
getActionValue
());
}
private
void
register
(
Student
student
,
String
operation
)
{
var
student
sToOperate
=
context
.
get
(
operation
);
if
(
student
sToOperate
==
null
)
{
student
sToOperate
=
new
ArrayList
<>();
private
void
register
(
Weapon
weapon
,
String
operation
)
{
var
weapon
sToOperate
=
context
.
get
(
operation
);
if
(
weapon
sToOperate
==
null
)
{
weapon
sToOperate
=
new
ArrayList
<>();
}
studentsToOperate
.
add
(
student
);
context
.
put
(
operation
,
student
sToOperate
);
weaponsToOperate
.
add
(
weapon
);
context
.
put
(
operation
,
weapon
sToOperate
);
}
/**
...
...
@@ -90,26 +90,26 @@ public class StudentRepository implements IUnitOfWork<Student> {
}
private
void
commitInsert
()
{
var
student
sToBeInserted
=
context
.
get
(
UnitActions
.
INSERT
.
getActionValue
());
for
(
var
student
:
student
sToBeInserted
)
{
LOGGER
.
info
(
"
Saving {} to database."
,
student
.
getName
());
studentDatabase
.
insert
(
student
);
var
weapon
sToBeInserted
=
context
.
get
(
UnitActions
.
INSERT
.
getActionValue
());
for
(
var
weapon
:
weapon
sToBeInserted
)
{
LOGGER
.
info
(
"
Inserting a new weapon {} to sales rack."
,
weapon
.
getName
());
weaponDatabase
.
insert
(
weapon
);
}
}
private
void
commitModify
()
{
var
modified
Student
s
=
context
.
get
(
UnitActions
.
MODIFY
.
getActionValue
());
for
(
var
student
:
modifiedStudent
s
)
{
LOGGER
.
info
(
"
Modifying {} to database."
,
student
.
getName
());
studentDatabase
.
modify
(
student
);
var
modified
Weapon
s
=
context
.
get
(
UnitActions
.
MODIFY
.
getActionValue
());
for
(
var
weapon
:
modifiedWeapon
s
)
{
LOGGER
.
info
(
"
Scheduling {} for modification work."
,
weapon
.
getName
());
weaponDatabase
.
modify
(
weapon
);
}
}
private
void
commitDelete
()
{
var
deleted
Student
s
=
context
.
get
(
UnitActions
.
DELETE
.
getActionValue
());
for
(
var
student
:
deletedStudent
s
)
{
LOGGER
.
info
(
"
Deleting {} to database."
,
student
.
getName
());
studentDatabase
.
delete
(
student
);
var
deleted
Weapon
s
=
context
.
get
(
UnitActions
.
DELETE
.
getActionValue
());
for
(
var
weapon
:
deletedWeapon
s
)
{
LOGGER
.
info
(
"
Scrapping {}."
,
weapon
.
getName
());
weaponDatabase
.
delete
(
weapon
);
}
}
}
unit-of-work/src/main/java/com/iluwatar/unitofwork/
Student
.java
→
unit-of-work/src/main/java/com/iluwatar/unitofwork/
Weapon
.java
浏览文件 @
2823166c
...
...
@@ -27,14 +27,12 @@ import lombok.Getter;
import
lombok.RequiredArgsConstructor
;
/**
* {@link
Student
} is an entity.
* {@link
Weapon
} is an entity.
*/
@Getter
@RequiredArgsConstructor
public
class
Student
{
public
class
Weapon
{
private
final
Integer
id
;
private
final
String
name
;
private
final
String
address
;
}
unit-of-work/src/main/java/com/iluwatar/unitofwork/
Student
Database.java
→
unit-of-work/src/main/java/com/iluwatar/unitofwork/
Weapon
Database.java
浏览文件 @
2823166c
...
...
@@ -24,19 +24,19 @@
package
com.iluwatar.unitofwork
;
/**
* Act as
Database for student
records.
* Act as
database for weapon
records.
*/
public
class
Student
Database
{
public
class
Weapon
Database
{
public
void
insert
(
Student
student
)
{
public
void
insert
(
Weapon
weapon
)
{
//Some insert logic to DB
}
public
void
modify
(
Student
student
)
{
public
void
modify
(
Weapon
weapon
)
{
//Some modify logic to DB
}
public
void
delete
(
Student
student
)
{
public
void
delete
(
Weapon
weapon
)
{
//Some delete logic to DB
}
}
unit-of-work/src/test/java/com/iluwatar/unitofwork/
StudentRepository
Test.java
→
unit-of-work/src/test/java/com/iluwatar/unitofwork/
ArmsDealer
Test.java
浏览文件 @
2823166c
...
...
@@ -36,102 +36,102 @@ import java.util.Map;
import
org.junit.jupiter.api.Test
;
/**
* tests {@link
StudentRepository
}
* tests {@link
ArmsDealer
}
*/
class
StudentRepository
Test
{
private
final
Student
student1
=
new
Student
(
1
,
"Ram"
,
"street 9, cupertino
"
);
private
final
Student
student2
=
new
Student
(
1
,
"Sham"
,
"Z bridge, pun
e"
);
class
ArmsDealer
Test
{
private
final
Weapon
weapon1
=
new
Weapon
(
1
,
"battle ram
"
);
private
final
Weapon
weapon2
=
new
Weapon
(
1
,
"wooden lanc
e"
);
private
final
Map
<
String
,
List
<
Student
>>
context
=
new
HashMap
<>();
private
final
StudentDatabase
studentDatabase
=
mock
(
Student
Database
.
class
);
private
final
StudentRepository
studentRepository
=
new
StudentRepository
(
context
,
student
Database
);;
private
final
Map
<
String
,
List
<
Weapon
>>
context
=
new
HashMap
<>();
private
final
WeaponDatabase
weaponDatabase
=
mock
(
Weapon
Database
.
class
);
private
final
ArmsDealer
armsDealer
=
new
ArmsDealer
(
context
,
weapon
Database
);;
@Test
void
shouldSaveNewStudentWithoutWritingToDb
()
{
studentRepository
.
registerNew
(
student
1
);
studentRepository
.
registerNew
(
student
2
);
armsDealer
.
registerNew
(
weapon
1
);
armsDealer
.
registerNew
(
weapon
2
);
assertEquals
(
2
,
context
.
get
(
UnitActions
.
INSERT
.
getActionValue
()).
size
());
verifyNoMoreInteractions
(
student
Database
);
verifyNoMoreInteractions
(
weapon
Database
);
}
@Test
void
shouldSaveDeletedStudentWithoutWritingToDb
()
{
studentRepository
.
registerDeleted
(
student
1
);
studentRepository
.
registerDeleted
(
student
2
);
armsDealer
.
registerDeleted
(
weapon
1
);
armsDealer
.
registerDeleted
(
weapon
2
);
assertEquals
(
2
,
context
.
get
(
UnitActions
.
DELETE
.
getActionValue
()).
size
());
verifyNoMoreInteractions
(
student
Database
);
verifyNoMoreInteractions
(
weapon
Database
);
}
@Test
void
shouldSaveModifiedStudentWithoutWritingToDb
()
{
studentRepository
.
registerModified
(
student
1
);
studentRepository
.
registerModified
(
student
2
);
armsDealer
.
registerModified
(
weapon
1
);
armsDealer
.
registerModified
(
weapon
2
);
assertEquals
(
2
,
context
.
get
(
UnitActions
.
MODIFY
.
getActionValue
()).
size
());
verifyNoMoreInteractions
(
student
Database
);
verifyNoMoreInteractions
(
weapon
Database
);
}
@Test
void
shouldSaveAllLocalChangesToDb
()
{
context
.
put
(
UnitActions
.
INSERT
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
MODIFY
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
DELETE
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
INSERT
.
getActionValue
(),
List
.
of
(
weapon
1
));
context
.
put
(
UnitActions
.
MODIFY
.
getActionValue
(),
List
.
of
(
weapon
1
));
context
.
put
(
UnitActions
.
DELETE
.
getActionValue
(),
List
.
of
(
weapon
1
));
studentRepository
.
commit
();
armsDealer
.
commit
();
verify
(
studentDatabase
,
times
(
1
)).
insert
(
student
1
);
verify
(
studentDatabase
,
times
(
1
)).
modify
(
student
1
);
verify
(
studentDatabase
,
times
(
1
)).
delete
(
student
1
);
verify
(
weaponDatabase
,
times
(
1
)).
insert
(
weapon
1
);
verify
(
weaponDatabase
,
times
(
1
)).
modify
(
weapon
1
);
verify
(
weaponDatabase
,
times
(
1
)).
delete
(
weapon
1
);
}
@Test
void
shouldNotWriteToDbIfContextIsNull
()
{
var
studentRepository
=
new
StudentRepository
(
null
,
student
Database
);
var
weaponRepository
=
new
ArmsDealer
(
null
,
weapon
Database
);
student
Repository
.
commit
();
weapon
Repository
.
commit
();
verifyNoMoreInteractions
(
student
Database
);
verifyNoMoreInteractions
(
weapon
Database
);
}
@Test
void
shouldNotWriteToDbIfNothingToCommit
()
{
var
studentRepository
=
new
StudentRepository
(
new
HashMap
<>(),
student
Database
);
var
weaponRepository
=
new
ArmsDealer
(
new
HashMap
<>(),
weapon
Database
);
student
Repository
.
commit
();
weapon
Repository
.
commit
();
verifyNoMoreInteractions
(
student
Database
);
verifyNoMoreInteractions
(
weapon
Database
);
}
@Test
void
shouldNotInsertToDbIfNoRegisteredStudentsToBeCommitted
()
{
context
.
put
(
UnitActions
.
MODIFY
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
DELETE
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
MODIFY
.
getActionValue
(),
List
.
of
(
weapon
1
));
context
.
put
(
UnitActions
.
DELETE
.
getActionValue
(),
List
.
of
(
weapon
1
));
studentRepository
.
commit
();
armsDealer
.
commit
();
verify
(
studentDatabase
,
never
()).
insert
(
student
1
);
verify
(
weaponDatabase
,
never
()).
insert
(
weapon
1
);
}
@Test
void
shouldNotModifyToDbIfNotRegisteredStudentsToBeCommitted
()
{
context
.
put
(
UnitActions
.
INSERT
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
DELETE
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
INSERT
.
getActionValue
(),
List
.
of
(
weapon
1
));
context
.
put
(
UnitActions
.
DELETE
.
getActionValue
(),
List
.
of
(
weapon
1
));
studentRepository
.
commit
();
armsDealer
.
commit
();
verify
(
studentDatabase
,
never
()).
modify
(
student
1
);
verify
(
weaponDatabase
,
never
()).
modify
(
weapon
1
);
}
@Test
void
shouldNotDeleteFromDbIfNotRegisteredStudentsToBeCommitted
()
{
context
.
put
(
UnitActions
.
INSERT
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
MODIFY
.
getActionValue
(),
List
.
of
(
student
1
));
context
.
put
(
UnitActions
.
INSERT
.
getActionValue
(),
List
.
of
(
weapon
1
));
context
.
put
(
UnitActions
.
MODIFY
.
getActionValue
(),
List
.
of
(
weapon
1
));
studentRepository
.
commit
();
armsDealer
.
commit
();
verify
(
studentDatabase
,
never
()).
delete
(
student
1
);
verify
(
weaponDatabase
,
never
()).
delete
(
weapon
1
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录