diff --git a/localization/zh/step-builder/README.md b/localization/zh/step-builder/README.md new file mode 100644 index 000000000..5e27f6f1d --- /dev/null +++ b/localization/zh/step-builder/README.md @@ -0,0 +1,24 @@ +--- +title: Step Builder +category: Creational +language: zn +tag: + - Instantiation +--- + +## 又被称为 +分步构建 + +## 目的 +这是构建者模式的一个扩展,完全指导用户创建对象,没有混淆的机会。 +用户体验会大大提升,因为他只能看到下一个步骤的方法,直到适当的时机才会出现构建对象的“build”方法。 + +## 类图 +![alt text](./etc/step-builder.png "Step Builder") + +## 应用 +使用分布构建模式当创建复杂对象的算法需要独立于组成对象的部分以及它们的组装方式,且构造过程必须允许对象有不同的表示形式,并且在此过程中顺序很重要时。 + +## 鸣谢 + +* [Marco Castigliego - Step Builder](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html) diff --git a/localization/zh/step-builder/etc/step-builder.png b/localization/zh/step-builder/etc/step-builder.png new file mode 100644 index 000000000..b7b623657 Binary files /dev/null and b/localization/zh/step-builder/etc/step-builder.png differ diff --git a/localization/zh/table-module/README.md b/localization/zh/table-module/README.md new file mode 100644 index 000000000..f8b404faa --- /dev/null +++ b/localization/zh/table-module/README.md @@ -0,0 +1,135 @@ +--- +title: Table Module +category: Structural +language: zh +tag: + - Data access +--- + +## 又被称为 +表模块 + +## Intent +表模块模式将域逻辑按数据库中的每个表组织为一个类,并且一个类的单个实例包含将对数据执行的各种过程。 + +## Explanation + +现实世界例子 + +> 当处理一个用户系统时,我们需要在用户表上进行一些操作。在这种情况下,我们可以使用表模块模式。我们可以创建一个名为 UserTableModule 的类,并初始化该类的一个实例,来处理用户表中所有行的业务逻辑。 + +直白点说 + +> 一个单独的实例,处理数据库表或视图中所有行的业务逻辑。 + +**编程实例** + +在用户系统的示例中,我们需要处理用户登录和用户注册的域逻辑。我们可以使用表模块模式,并创建UserTableModule类的一个实例来处理用户表中所有行的业务逻辑。 + +以下是基本的User实体。 + +```java +@Setter +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +public class User { + private int id; + private String username; + private String password; +} +``` + +下面的是 `UserTableModule` 类. + +```java +public class UserTableModule { + private final DataSource dataSource; + private Connection connection = null; + private ResultSet resultSet = null; + private PreparedStatement preparedStatement = null; + + public UserTableModule(final DataSource userDataSource) { + this.dataSource = userDataSource; + } + + /** + * Login using username and password. + * + * @param username the username of a user + * @param password the password of a user + * @return the execution result of the method + * @throws SQLException if any error + */ + public int login(final String username, final String password) throws SQLException { + // Method implementation. + + } + + /** + * Register a new user. + * + * @param user a user instance + * @return the execution result of the method + * @throws SQLException if any error + */ + public int registerUser(final User user) throws SQLException { + // Method implementation. + } +} +``` + +在App类中,我们使用UserTableModule的一个实例来处理用户登录和注册。 + +```java +// Create data source and create the user table. +final var dataSource = createDataSource(); +createSchema(dataSource); +userTableModule = new UserTableModule(dataSource); + +//Initialize two users. +var user1 = new User(1, "123456", "123456"); +var user2 = new User(2, "test", "password"); + +//Login and register using the instance of userTableModule. +userTableModule.registerUser(user1); +userTableModule.login(user1.getUsername(), user1.getPassword()); +userTableModule.login(user2.getUsername(), user2.getPassword()); +userTableModule.registerUser(user2); +userTableModule.login(user2.getUsername(), user2.getPassword()); + +deleteSchema(dataSource); +``` + +程序输出: + +```java +12:22:13.095 [main] INFO com.iluwatar.tablemodule.UserTableModule - Register successfully! +12:22:13.117 [main] INFO com.iluwatar.tablemodule.UserTableModule - Login successfully! +12:22:13.128 [main] INFO com.iluwatar.tablemodule.UserTableModule - Fail to login! +12:22:13.136 [main] INFO com.iluwatar.tablemodule.UserTableModule - Register successfully! +12:22:13.144 [main] INFO com.iluwatar.tablemodule.UserTableModule - Login successfully! +``` + +## 类图 + +![](etc/table-module.urm.png "table module") + +## 应用 +使用表模块模式当: + +- 域逻辑简单且数据呈表格形式。 +- 应用程序仅使用少量共享的常见的面向表格的数据结构。 + +## 教学 + +- [Transaction Script](https://java-design-patterns.com/patterns/transaction-script/) + +- [Domain Model](https://java-design-patterns.com/patterns/domain-model/) + +## 鸣谢 + +* [Table Module Pattern](http://wiki3.cosc.canterbury.ac.nz/index.php/Table_module_pattern) +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=18acc13ba60d66690009505577c45c04) +* [Architecture patterns: domain model and friends](https://inviqa.com/blog/architecture-patterns-domain-model-and-friends) \ No newline at end of file diff --git a/localization/zh/table-module/etc/table-module.urm.png b/localization/zh/table-module/etc/table-module.urm.png new file mode 100644 index 000000000..9c4bc0b18 Binary files /dev/null and b/localization/zh/table-module/etc/table-module.urm.png differ diff --git a/localization/zh/unit-of-work/README.md b/localization/zh/unit-of-work/README.md new file mode 100644 index 000000000..a957390e8 --- /dev/null +++ b/localization/zh/unit-of-work/README.md @@ -0,0 +1,203 @@ +--- +title: Unit Of Work +category: Architectural +language: zn +tag: + - Data access + - Performance +--- + +## 又被称为 +工作单元 + +## 目的 + +当一个业务事务完成时,所有的更新都作为一个大的工作单元一次性发送,以最小化数据库的往返次数进行持久化。 + +## 解释 + +现实世界例子 + +> 武器商人拥有一个包含武器信息的数据库。 +> 全城的商贩们都在不断地更新这些信息,这导致数据库服务器的负载很高。 +> 为了使负载更易于管理,我们应用了工作单元模式,将许多小的更新批量发送。 + +用直白的话来说 + +> 工作单元将许多小的数据库更新合并成一个批次。 +> 以优化往返次数。 + +[MartinFowler.com](https://martinfowler.com/eaaCatalog/unitOfWork.html) 中说 + +> 维护一个受业务事务影响的对象列表。 +> 并协调写出更改和解决并发问题。 + +**编程样例** + +以下是要持久化到数据库中的 `Weapon` 的实体。 + +```java +@Getter +@RequiredArgsConstructor +public class Weapon { + private final Integer id; + private final String name; +} +``` + +实现的核心是 `ArmsDealer` 实现了工作单元模式。 +它维护了一个需要完成的数据库操作映射 (`context`) 当调用 `commit` 时 +它会一次性批量应用这些操作。 + +```java +public interface IUnitOfWork { + + String INSERT = "INSERT"; + String DELETE = "DELETE"; + String MODIFY = "MODIFY"; + + void registerNew(T entity); + + void registerModified(T entity); + + void registerDeleted(T entity); + + void commit(); +} + +@Slf4j +@RequiredArgsConstructor +public class ArmsDealer implements IUnitOfWork { + + private final Map> 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()); + } + + @Override + public void registerModified(Weapon weapon) { + LOGGER.info("Registering {} for modify in context.", weapon.getName()); + register(weapon, UnitActions.MODIFY.getActionValue()); + + } + + @Override + public void registerDeleted(Weapon weapon) { + LOGGER.info("Registering {} for delete in context.", weapon.getName()); + register(weapon, UnitActions.DELETE.getActionValue()); + } + + 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); + } + + /** + * 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."); + } + + 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 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 deletedWeapons = context.get(UnitActions.DELETE.getActionValue()); + for (var weapon : deletedWeapons) { + LOGGER.info("Scrapping {}.", weapon.getName()); + weaponDatabase.delete(weapon); + } + } +} +``` + +以下描述了整个应用是如何组装起来的。 + +```java +// 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>(), new WeaponDatabase()); + +// perform operations on the weapons +weaponRepository.registerNew(enchantedHammer); +weaponRepository.registerModified(silverTrident); +weaponRepository.registerDeleted(brokenGreatSword); +weaponRepository.commit(); +``` + +以下是控制台输出。 + +``` +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. +``` + +## 类图 + +![alt text](./etc/unit-of-work.urm.png "unit-of-work") + +## 应用 + +在以下情况时使用单元模式 + +* 为了优化数据库事务所需的时间。 +* 作为工作单元将更改发送到数据库,确保事务的原子性。 +* 为了减少数据库调用的次数。 + +## 教程 + +* [Repository and Unit of Work Pattern](https://www.programmingwithwolfgang.com/repository-and-unit-of-work-pattern/) +* [Unit of Work - a Design Pattern](https://mono.software/2017/01/13/unit-of-work-a-design-pattern/) + +## 鸣谢 + +* [Design Pattern - Unit Of Work Pattern](https://www.codeproject.com/Articles/581487/Unit-of-Work-Design-Pattern) +* [Unit Of Work](https://martinfowler.com/eaaCatalog/unitOfWork.html) +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a) diff --git a/localization/zh/unit-of-work/etc/unit-of-work.urm.png b/localization/zh/unit-of-work/etc/unit-of-work.urm.png new file mode 100644 index 000000000..bb192af54 Binary files /dev/null and b/localization/zh/unit-of-work/etc/unit-of-work.urm.png differ diff --git a/localization/zh/update-method/README.md b/localization/zh/update-method/README.md new file mode 100644 index 000000000..64038e34e --- /dev/null +++ b/localization/zh/update-method/README.md @@ -0,0 +1,36 @@ +--- +title: Update Method +category: Behavioral +language: zn +tag: + - Game programming +--- + +## 又被称为 +更新方法 + +## 目的 +更新方法模式通过告诉每个对象一次处理一个行为帧来模拟一组独立的对象。 + +## 解释 +游戏世界维护了一个对象的集合。每个对象都实现了一个更新方法,用来模拟该对象行为的一帧。在每一帧中,游戏会更新集合中的每一个对象。 + +要了解更多关于游戏循环是如何运行的,以及何时调用更新方法,请参考“游戏循环模式”。 + +## 类图 +![alt text](./etc/update-method.urm.png "Update Method pattern class diagram") + +## 应用 +如果说游戏循环模式是自切面包以来最好的东西,那么更新方法模式就是它的黄油。有很多玩家与动态实体互动的游戏都以某种形式使用这个模式。如果游戏里有宇航兵、龙、火星人、幽灵或运动员,那么它很可能使用了这种模式。 + +然而,如果游戏更为抽象,且移动的部分不像是生动的角色,而更像是棋盘上的棋子,那么这种模式往往并不合适。在像国际象棋这样的游戏中,你不需要同时模拟所有的棋子,也可能不需要告诉每一个兵卒在每一帧都更新自己。 + +当以下情况发生时,更新方法工作得很好: + +- 你的游戏中有许多对象或系统需要同时运行。 +- 每个对象的行为大部分都独立于其他对象。 +- 这些对象需要随时间进行模拟。 + +## 鸣谢 + +* [Game Programming Patterns - Update Method](http://gameprogrammingpatterns.com/update-method.html) diff --git a/localization/zh/update-method/etc/update-method.urm.png b/localization/zh/update-method/etc/update-method.urm.png new file mode 100644 index 000000000..ddc47b5fe Binary files /dev/null and b/localization/zh/update-method/etc/update-method.urm.png differ diff --git a/localization/zh/value-object/README.md b/localization/zh/value-object/README.md new file mode 100644 index 000000000..59a76d978 --- /dev/null +++ b/localization/zh/value-object/README.md @@ -0,0 +1,96 @@ +--- +title: Value Object +category: Creational +language: zn +tag: + - Instantiation +--- + +## 又被称为 +值对象 + +## 目的 + +提供的对象应遵循值语义而不是引用语义。这意味着两个值对象的相等性不是基于它们的身份。只要两个值对象的值相同,即使它们不是同一个对象,它们也被认为是相等的。 + +## 解释 + +现实世界例子 + +> 在一个角色扮演游戏中,有一个用于英雄属性统计的类。 +> 这些统计属性包括力量、智慧和运气等特征。 +> 当所有的属性都相同时,不同英雄的统计数据应被认为是相等的。 + +用直白的话来说 + +> 当值对象的属性有相同的值时,它们是相等的。 + +维基百科中说 + +> 在计算机科学中,值对象是一个代表简单实体的小对象。 +> 其相等性不是基于身份的:即当两个值对象有相同的值的时候。 +> 它们是相等的,而不必要是同一个对象。 + +**编程样例** + +这里是作为值对象的 `HeroStat` 类。 请注意使用了 +[Lombok's `@Value`](https://projectlombok.org/features/Value) 注解。 + +```java +@Value(staticConstructor = "valueOf") +class HeroStat { + + int strength; + int intelligence; + int luck; +} +``` + +这个示例创建了三个不同的 `HeroStat`s 并比较了它们的相等性。 + +```java +var statA = HeroStat.valueOf(10, 5, 0); +var statB = HeroStat.valueOf(10, 5, 0); +var statC = HeroStat.valueOf(5, 1, 8); + +LOGGER.info(statA.toString()); +LOGGER.info(statB.toString()); +LOGGER.info(statC.toString()); + +LOGGER.info("Is statA and statB equal : {}", statA.equals(statB)); +LOGGER.info("Is statA and statC equal : {}", statA.equals(statC)); +``` + +以下是控制台的输出。 + +``` +20:11:12.199 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0) +20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0) +20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=5, intelligence=1, luck=8) +20:11:12.202 [main] INFO com.iluwatar.value.object.App - Is statA and statB equal : true +20:11:12.203 [main] INFO com.iluwatar.value.object.App - Is statA and statC equal : false +``` + +## 类图 + +![alt text](./etc/value-object.png "Value Object") + +## 应用 + +当满足以下情况时,使用值对象: + +* 对象的相等性需要基于对象的值 + +## 现实世界的案例 + +* [java.util.Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) +* [java.time.LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html) +* [joda-time, money, beans](http://www.joda.org/) + +## 鸣谢 + +* [Patterns of Enterprise Application Architecture](http://www.martinfowler.com/books/eaa.html) +* [ValueObject](https://martinfowler.com/bliki/ValueObject.html) +* [VALJOs - Value Java Objects : Stephen Colebourne's blog](http://blog.joda.org/2014/03/valjos-value-java-objects.html) +* [Value Object : Wikipedia](https://en.wikipedia.org/wiki/Value_object) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) diff --git a/localization/zh/value-object/etc/value-object.png b/localization/zh/value-object/etc/value-object.png new file mode 100644 index 000000000..69a244c80 Binary files /dev/null and b/localization/zh/value-object/etc/value-object.png differ