From 068fa0371e90c072741752150c2585b818456fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=9E=97=E9=A2=96?= Date: Fri, 7 May 2021 01:57:16 +0800 Subject: [PATCH] docs: Translate some of the README docs into Chinese (#1744) * docs: translated docs to zh * docs: translated doc of sharding pattern to Chinese * docs: translated doc of factory pattern to Chinese * docs: translated doc of factory-kit pattern to Chinese Co-authored-by: Subhrodip Mohanta --- zh/circuit-breaker/README.md | 312 ++++++++++++++++++++++++++++ zh/collection-pipeline/README.md | 29 +++ zh/composite-entity/README.md | 121 +++++++++++ zh/data-bus/README.md | 31 +++ zh/data-mapper/README.md | 25 +++ zh/double-checked-locking/README.md | 21 ++ zh/factory-kit/README.md | 27 +++ zh/factory/README.md | 141 +++++++++++++ zh/sharding/README.md | 30 +++ 9 files changed, 737 insertions(+) create mode 100644 zh/circuit-breaker/README.md create mode 100644 zh/collection-pipeline/README.md create mode 100644 zh/composite-entity/README.md create mode 100644 zh/data-bus/README.md create mode 100644 zh/data-mapper/README.md create mode 100644 zh/double-checked-locking/README.md create mode 100644 zh/factory-kit/README.md create mode 100644 zh/factory/README.md create mode 100644 zh/sharding/README.md diff --git a/zh/circuit-breaker/README.md b/zh/circuit-breaker/README.md new file mode 100644 index 000000000..1f2eaea76 --- /dev/null +++ b/zh/circuit-breaker/README.md @@ -0,0 +1,312 @@ +--- +layout: pattern +title: Circuit Breaker +folder: circuit-breaker +permalink: /patterns/circuit-breaker/ +categories: Behavioral +tags: + - Performance + - Decoupling + - Cloud distributed +--- + +## 含义 + +以这样的方式(译者:指断路器方式)处理昂贵的远程服务调用,可以防止单个服务/组件的故障导致整个应用程序崩溃,同时我们可以尽快地进行服务重连。 + +## 解释 + +现实世界案例 + +> 设想一下,一个网络应用程序既有本地文件/图像,又有用于获取数据的远程服务。这些远程服务可能在某些时候是健康的、有反应的,也可能在某些时候由于各种原因而变得缓慢和无反应。因此,如果其中一个远程服务速度慢或不能成功响应,我们的应用程序将尝试使用多个线程/进程从远程服务中获取响应,很快所有的线程/进程都会挂起(也称为线程饥饿 thread starvation),从而导致我们整个 Web 应用程序崩溃。我们应该能够检测到这种情况,并向用户显示一个适当的信息,以便用户可以探索应用程序的其他部分,而不受远程服务故障的影响。同时,其他正常工作的服务应该保持运作,不受这次故障的影响。 + +简而言之 + +> 断路器允许优雅地处理失败的远程服务。当我们的应用程序的所有部分都高度解耦时,这种方式的效果会很好,一个组件的失败并不会导致其他部分停止工作。 + +维基百科的解释 + +> 断路器是现代软件开发中使用的一种设计模式。它用于检测故障,并封装了防止故障不断复发的逻辑,在维护期间,临时地处理外部系统故障或意外的系统问题。 + +## Programmatic Example + +那么,这一切是如何实现的呢?考虑到上面的例子,我们将在一个简单的例子中模拟这个功能。一个监控服务(译者:下图的 Monitoring Service)模拟了网络应用,进行本地和远程调用。 + +该服务架构如下: + +![alt text](../../circuit-breaker/etc/ServiceDiagram.png "Service Diagram") + +终端用户(译者:上图的 End User)应用的代码如下: + +```java +@Slf4j +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + + var serverStartTime = System.nanoTime(); + + var delayedService = new DelayedRemoteService(serverStartTime, 5); + var delayedServiceCircuitBreaker = new DefaultCircuitBreaker(delayedService, 3000, 2, + 2000 * 1000 * 1000); + + var quickService = new QuickRemoteService(); + var quickServiceCircuitBreaker = new DefaultCircuitBreaker(quickService, 3000, 2, + 2000 * 1000 * 1000); + + //Create an object of monitoring service which makes both local and remote calls + var monitoringService = new MonitoringService(delayedServiceCircuitBreaker, + quickServiceCircuitBreaker); + + //Fetch response from local resource + LOGGER.info(monitoringService.localResourceResponse()); + + //Fetch response from delayed service 2 times, to meet the failure threshold + LOGGER.info(monitoringService.delayedServiceResponse()); + LOGGER.info(monitoringService.delayedServiceResponse()); + + //Fetch current state of delayed service circuit breaker after crossing failure threshold limit + //which is OPEN now + LOGGER.info(delayedServiceCircuitBreaker.getState()); + + //Meanwhile, the delayed service is down, fetch response from the healthy quick service + LOGGER.info(monitoringService.quickServiceResponse()); + LOGGER.info(quickServiceCircuitBreaker.getState()); + + //Wait for the delayed service to become responsive + try { + LOGGER.info("Waiting for delayed service to become responsive"); + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //Check the state of delayed circuit breaker, should be HALF_OPEN + LOGGER.info(delayedServiceCircuitBreaker.getState()); + + //Fetch response from delayed service, which should be healthy by now + LOGGER.info(monitoringService.delayedServiceResponse()); + //As successful response is fetched, it should be CLOSED again. + LOGGER.info(delayedServiceCircuitBreaker.getState()); + } +} +``` + +监控服务代码(译者:上图的 monitoring service): + +```java +public class MonitoringService { + + private final CircuitBreaker delayedService; + + private final CircuitBreaker quickService; + + public MonitoringService(CircuitBreaker delayedService, CircuitBreaker quickService) { + this.delayedService = delayedService; + this.quickService = quickService; + } + + //Assumption: Local service won't fail, no need to wrap it in a circuit breaker logic + public String localResourceResponse() { + return "Local Service is working"; + } + + /** + * Fetch response from the delayed service (with some simulated startup time). + * + * @return response string + */ + public String delayedServiceResponse() { + try { + return this.delayedService.attemptRequest(); + } catch (RemoteServiceException e) { + return e.getMessage(); + } + } + + /** + * Fetches response from a healthy service without any failure. + * + * @return response string + */ + public String quickServiceResponse() { + try { + return this.quickService.attemptRequest(); + } catch (RemoteServiceException e) { + return e.getMessage(); + } + } +} +``` +可以看出,它直接进行了获取本地资源的调用,但它把对远程(昂贵的)服务的调用包装在一个断路器对象中,这样可以防止出现如下故障: + +```java +public class DefaultCircuitBreaker implements CircuitBreaker { + + private final long timeout; + private final long retryTimePeriod; + private final RemoteService service; + long lastFailureTime; + private String lastFailureResponse; + int failureCount; + private final int failureThreshold; + private State state; + private final long futureTime = 1000 * 1000 * 1000 * 1000; + + /** + * Constructor to create an instance of Circuit Breaker. + * + * @param timeout Timeout for the API request. Not necessary for this simple example + * @param failureThreshold Number of failures we receive from the depended service before changing + * state to 'OPEN' + * @param retryTimePeriod Time period after which a new request is made to remote service for + * status check. + */ + DefaultCircuitBreaker(RemoteService serviceToCall, long timeout, int failureThreshold, + long retryTimePeriod) { + this.service = serviceToCall; + // We start in a closed state hoping that everything is fine + this.state = State.CLOSED; + this.failureThreshold = failureThreshold; + // Timeout for the API request. + // Used to break the calls made to remote resource if it exceeds the limit + this.timeout = timeout; + this.retryTimePeriod = retryTimePeriod; + //An absurd amount of time in future which basically indicates the last failure never happened + this.lastFailureTime = System.nanoTime() + futureTime; + this.failureCount = 0; + } + + // Reset everything to defaults + @Override + public void recordSuccess() { + this.failureCount = 0; + this.lastFailureTime = System.nanoTime() + futureTime; + this.state = State.CLOSED; + } + + @Override + public void recordFailure(String response) { + failureCount = failureCount + 1; + this.lastFailureTime = System.nanoTime(); + // Cache the failure response for returning on open state + this.lastFailureResponse = response; + } + + // Evaluate the current state based on failureThreshold, failureCount and lastFailureTime. + protected void evaluateState() { + if (failureCount >= failureThreshold) { //Then something is wrong with remote service + if ((System.nanoTime() - lastFailureTime) > retryTimePeriod) { + //We have waited long enough and should try checking if service is up + state = State.HALF_OPEN; + } else { + //Service would still probably be down + state = State.OPEN; + } + } else { + //Everything is working fine + state = State.CLOSED; + } + } + + @Override + public String getState() { + evaluateState(); + return state.name(); + } + + /** + * Break the circuit beforehand if it is known service is down Or connect the circuit manually if + * service comes online before expected. + * + * @param state State at which circuit is in + */ + @Override + public void setState(State state) { + this.state = state; + switch (state) { + case OPEN: + this.failureCount = failureThreshold; + this.lastFailureTime = System.nanoTime(); + break; + case HALF_OPEN: + this.failureCount = failureThreshold; + this.lastFailureTime = System.nanoTime() - retryTimePeriod; + break; + default: + this.failureCount = 0; + } + } + + /** + * Executes service call. + * + * @return Value from the remote resource, stale response or a custom exception + */ + @Override + public String attemptRequest() throws RemoteServiceException { + evaluateState(); + if (state == State.OPEN) { + // return cached response if the circuit is in OPEN state + return this.lastFailureResponse; + } else { + // Make the API request if the circuit is not OPEN + try { + //In a real application, this would be run in a thread and the timeout + //parameter of the circuit breaker would be utilized to know if service + //is working. Here, we simulate that based on server response itself + var response = service.call(); + // Yay!! the API responded fine. Let's reset everything. + recordSuccess(); + return response; + } catch (RemoteServiceException ex) { + recordFailure(ex.getMessage()); + throw ex; + } + } + } +} +``` + +上述模式是如何防止失败的呢?让我们通过它所实现的这个有限状态机来了解。 + +![alt text](../../circuit-breaker/etc/StateDiagram.png "State Diagram") + +- 我们用 `timeout`(超时)、 `failureThreshold` (失败阈值)、`retryTimePeriod`(重试时间周期) 参数初始化断路器对象 ,用于确定 API 的适应性。 +- 最初,断路器处于 `closed` 关闭状态,没有发生对 API 的远程调用。 +- 每次调用成功,我们就把状态重置为开始时的样子。 +- 如果失败的次数超过了一定的阈值(`failureThreshold`),断路器就会进入 `open` 开启状态,它的作用就像一个开启的电路,阻止远程服务的调用,从而节省资源。 +- 一旦我们超过重试时间周期(`retryTimePeriod`),断路器就会转到 `half-open` 半启用状态,并再次调用远程服务,检查服务是否正常,以便我们可以提供最新的响应内容。如果远程服务调用失败会使断路器回到 `open` 状态,并在重试超时后进行另一次尝试;如果远程服务调用成功则使断路器进入 `closed` 状态,这样一切又开始正常工作。 + +## 类图 + +![alt text](../../circuit-breaker/etc/circuit-breaker.urm.png "Circuit Breaker class diagram") + +## 适用场景 + +在以下场景下,可以使用断路器模式: + +- 构建一个高可用的应用程序,某些些服务的失败不会导致整个应用程序的崩溃。 +- 构建一个持续运行(长期在线)的应用程序,以便其组件可以在不完全关闭的情况下进行升级。 + +## 相关模式 + +- [Retry Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/retry) + +## 现实案例 + +* [Spring Circuit Breaker module](https://spring.io/guides/gs/circuit-breaker) +* [Netflix Hystrix API](https://github.com/Netflix/Hystrix) + +## 引用 + +* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42) +* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html) +* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a) +* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker) \ No newline at end of file diff --git a/zh/collection-pipeline/README.md b/zh/collection-pipeline/README.md new file mode 100644 index 000000000..87613100c --- /dev/null +++ b/zh/collection-pipeline/README.md @@ -0,0 +1,29 @@ +--- +layout: pattern +title: Collection Pipeline +folder: collection-pipeline +permalink: /patterns/collection-pipeline/ +categories: Functional +tags: + - Reactive +--- + +## 释义 +**集合管道(Collection Pipeline)**包含**函数组合(Function Composition)**和**集合管道(Collection Pipeline)**两组合概念,这是两种函数式编程模式,你可以在代码中结合这两种模式来进行集合迭代。 +在函数式编程中,可以通过一系列较小的模块化函数或操作来编排复杂的操作。这一系列函数被称为函数组合。当一个数据集合流经一个函数组合时,它就成为一个集合管道。函数组合和集合管道是函数式编程中经常使用的两种设计模式。 + +## 类图 +![alt text](../../collection-pipeline/etc/collection-pipeline.png "Collection Pipeline") + +## 适用场景 +在以下场景适用集合管道模式: + +* 当你想执行一组连续的算子操作,其中一个算子收集的输出需要被输入到下一个算子中 +* 当你在代码中需要使用大量的中间状态语句时 +* 当你在代码中使用大量的循环语句时 + +## 引用 + +* [Function composition and the Collection Pipeline pattern](https://www.ibm.com/developerworks/library/j-java8idioms2/index.html) +* [Martin Fowler](https://martinfowler.com/articles/collection-pipeline/) +* [Java8 Streams](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html) \ No newline at end of file diff --git a/zh/composite-entity/README.md b/zh/composite-entity/README.md new file mode 100644 index 000000000..f38f30903 --- /dev/null +++ b/zh/composite-entity/README.md @@ -0,0 +1,121 @@ +--- +layout: pattern +title: Composite Entity +folder: composite-entity +permalink: /patterns/composite-entity/ +categories: Structural +tags: + - Enterprise Integration Pattern +--- + +## 含义 + +复合实体模式用于对一组相关联的持久化对象进行建模、描述和管理,用于取代对这组对象描述为单独粒度的实体。 + +## 解释 + +现实例子 + +> 对于一个控制台对象,需要管理许多接口功能。通过使用复合实体模式,将消息对象、信号对象等依赖性对象组合在一起,直接使用单个对象对其进行控制。 + +简单地说 + +> 复合实体模式允许使用一个统一对象来管理一组相互关联的对象 + +**编程示例** + +我们需要一个通用的解决方案来解决上述的控制台问题。我们引入了以下的通用复合对象。 + +```java +public abstract class DependentObject { + + T data; + + public void setData(T message) { + this.data = message; + } + + public T getData() { + return data; + } +} + +public abstract class CoarseGrainedObject { + + DependentObject[] dependentObjects; + + public void setData(T... data) { + IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i])); + } + + public T[] getData() { + return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray(); + } +} + +``` + +专用的 `console` 复合实体继承自这个基类,如下所示。 + +```java +public class MessageDependentObject extends DependentObject { + +} + +public class SignalDependentObject extends DependentObject { + +} + +public class ConsoleCoarseGrainedObject extends CoarseGrainedObject { + + @Override + public String[] getData() { + super.getData(); + return new String[]{ + dependentObjects[0].getData(), dependentObjects[1].getData() + }; + } + + public void init() { + dependentObjects = new DependentObject[]{ + new MessageDependentObject(), new SignalDependentObject()}; + } +} + +public class CompositeEntity { + + private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject(); + + public void setData(String message, String signal) { + console.setData(message, signal); + } + + public String[] getData() { + return console.getData(); + } +} +``` + +现在我们使用 `console` 复合实体来进行消息对象、信号对象的分配。 + +```java +var console = new CompositeEntity(); +console.init(); +console.setData("No Danger", "Green Light"); +Arrays.stream(console.getData()).forEach(LOGGER::info); +console.setData("Danger", "Red Light"); +Arrays.stream(console.getData()).forEach(LOGGER::info); +``` + +## 类图 + +![alt text](../../composite-entity/etc/composite_entity.urm.png "Composite Entity Pattern") + +## 适用场景 + +复合实体模式适用于以下场景: + +* 你想要通过一个对象来管理多个依赖对象,已调整对象之间的细化程度。同时将依赖对象的生命周期托管到这个粗粒度的复合实体对象。 +## 引用 + +* [Composite Entity Pattern in wikipedia](https://en.wikipedia.org/wiki/Composite_entity_pattern) \ No newline at end of file diff --git a/zh/data-bus/README.md b/zh/data-bus/README.md new file mode 100644 index 000000000..4eaa98914 --- /dev/null +++ b/zh/data-bus/README.md @@ -0,0 +1,31 @@ +--- +layout: pattern +title: Data Bus +folder: data-bus +permalink: /patterns/data-bus/ + +categories: Architectural +tags: + - Decoupling +--- + +## 含义 + +数据总线模式(译者:实际上,就是 Event-Bus 消息总线模式)允许在一个应用程序的组件之间收发消息/事件,而不需要这些组件相互感知,它们只需要知道所发送/接收的消息/事件的类型即可。 + +## 类图 +![data bus pattern uml diagram](../../data-bus/etc/data-bus.urm.png "Data Bus pattern") + +## 适用场景 +可以在以下场景使用数据总线模式: + +* 你希望由你的组件自己决定要接收哪些信息/事件 +* 你希望实现多对多的通信 +* 你希望你的组件不需要感知彼此 + +## 相关模式 +数据总线类似于以下设计模式: + +* 中介者模式(Mediator pattern),由数据总线成员自己决定是否要接受任何给定的消息。 +* 观察者模式(Observer pattern),但进一步支持了多对多的通信。 +* 发布/订阅模式(Publish/Subscribe pattern),但是数据总线将发布者和订阅者解耦。 \ No newline at end of file diff --git a/zh/data-mapper/README.md b/zh/data-mapper/README.md new file mode 100644 index 000000000..4dc268fdb --- /dev/null +++ b/zh/data-mapper/README.md @@ -0,0 +1,25 @@ +--- +layout: pattern +title: Data Mapper +folder: data-mapper +permalink: /patterns/data-mapper/ +categories: Architectural +tags: + - Decoupling +--- + +## 含义 +一个用于在持久化对象和数据库之间传输数据的映射器,同时保持它们之间和映射器本身的独立性。 + +## 类图 +![alt text](../../data-mapper/etc/data-mapper.png "Data Mapper") + +## 适用场景 +数据映射器适用于以下场景: + +* 当你想把数据对象从数据库访问层解耦时时 +* 当你想编写多个数据查询/持久化实现时 + +## 引用 + +* [Data Mapper](http://richard.jp.leguen.ca/tutoring/soen343-f2010/tutorials/implementing-data-mapper/) \ No newline at end of file diff --git a/zh/double-checked-locking/README.md b/zh/double-checked-locking/README.md new file mode 100644 index 000000000..5a8a6312d --- /dev/null +++ b/zh/double-checked-locking/README.md @@ -0,0 +1,21 @@ +--- +layout: pattern +title: Double Checked Locking +folder: double-checked-locking +permalink: /patterns/double-checked-locking/ +categories: Idiom +tags: + - Performance +--- + +## 含义 +通过先测试锁定标准("锁提示")而不实际获取锁的方式来减少获取锁的开销。只有当锁定标准检查表明需要锁定时,才进行实际的锁定逻辑。 + +## 类图 +![alt text](../../double-checked-locking/etc/double_checked_locking_1.png "Double Checked Locking") + +## 适用场景 +在以下场景适合使用双重锁检查模式: + +* 在创建对象时有存在并发的访问。如单例模式中,你想创建同一个类的单个实例,如果存在两个或更多的线程对实例进行判空,仅仅检查该该实例是否为空可能是不够的。 +* 在一个方法上存在并发访问,该方法的行为是根据一些约束条件而改变,而这些约束条件在该方法中也会发生变化。 \ No newline at end of file diff --git a/zh/factory-kit/README.md b/zh/factory-kit/README.md new file mode 100644 index 000000000..4f4b58b59 --- /dev/null +++ b/zh/factory-kit/README.md @@ -0,0 +1,27 @@ +--- +layout: pattern +title: Factory Kit +folder: factory-kit +permalink: /patterns/factory-kit/ +categories: Creational +tags: + - Extensibility +--- + +## 含义 +使用分离的构建器和工厂接口来定义一个不可变内容的工厂。 + +## 类图 +![alt text](../../factory-kit/etc/factory-kit.png "Factory Kit") + +## 适用场景 +工厂套件模式适用于与以下场景: + +* 一个类无法预知它需要创建的对象的类别 +- 你只是想要一个新的自定义构建器(builder)的实例,而非全局的构建器 +- 你明确地想要定义对象的类型,而且工厂可以创建这些对象 +- 你想要分离构建器(builder)和创建器(creator)接口 + +## 引用 + +* [Design Pattern Reloaded by Remi Forax: ](https://www.youtube.com/watch?v=-k2X7guaArU) \ No newline at end of file diff --git a/zh/factory/README.md b/zh/factory/README.md new file mode 100644 index 000000000..414f1e7a9 --- /dev/null +++ b/zh/factory/README.md @@ -0,0 +1,141 @@ +--- +layout: pattern +title: Factory +folder: factory +permalink: /patterns/factory/ +categories: Creational +tags: + - Gang of Four +--- + +## 也被称为 + +* 简单工厂 +* 静态工厂方法 + +## 含义 + +在工厂类中提供一个封装的静态工厂方法,用于隐藏对象初始化细节,使客户端代码可以专注于使用,而不用关心类的初始化过程。 + +## 解释 + +现实例子 + +> +> 假设我们有一个需要连接到 SQL Server 的 Web 应用,但现在我们需要切换到连接 Oracle。为了不修改现有代码的情况下做到这一点,我们需要实现简单工厂模式。在这种模式下,可以通过调用一个静态方法来创建与给定数据库的连接。 + +维基百科 + +> 工厂类是一个用于创建其他对象的对象 -- 从形式上看,工厂方法是一个用于返回不同原型或类型的函数或方法。 + +**编程示例** + +我们有一个 `Car` 接口,以及实现类 `Ford`, `Ferrari`。 + +```java +public interface Car { + String getDescription(); +} + +public class Ford implements Car { + + static final String DESCRIPTION = "This is Ford."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class Ferrari implements Car { + + static final String DESCRIPTION = "This is Ferrari."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} +``` + +Enumeration above represents types of cars that we support (`Ford` and `Ferrari`). + +以下的枚举用于表示支持的 `Car` 类型(`Ford` 和 `Ferrari`) + +```java +public enum CarType { + + FORD(Ford::new), + FERRARI(Ferrari::new); + + private final Supplier constructor; + + CarType(Supplier constructor) { + this.constructor = constructor; + } + + public Supplier getConstructor() { + return this.constructor; + } +} +``` +接着我们实现了一个静态方法 `getCar` 用于封装工厂类 `CarsFactory` 创建 `Car` 具体对象实例的细节。 + +```java +public class CarsFactory { + + public static Car getCar(CarType type) { + return type.getConstructor().get(); + } +} +``` + +现在我们可以在客户端代码中通过工厂类创建不同类型的 `Car` 对象实例。 + +```java +var car1 = CarsFactory.getCar(CarType.FORD); +var car2 = CarsFactory.getCar(CarType.FERRARI); +LOGGER.info(car1.getDescription()); +LOGGER.info(car2.getDescription()); +``` + +程序输出: + +```java +This is Ford. +This is Ferrari. +``` + +## 类图 + +![alt text](../../factory/etc/factory.urm.png "Factory pattern class diagram") + +## 适用场景 + +在你只关心对象的创建,但不关心如何创建、管理它的时候,请使用简单工厂模式。 + +**优点** + +* 可以把对象创建代码集中在一个地方,避免在代码库存散布 "new" 关键字。 +* 可以让代码更加低耦合。它的一些主要优点包括更好的可测试性、更好的可读性、组件可替换性、可拓展性、更好的隔离性。 + +**缺点** + +* 会使代码变得比原来的更加复杂一些。 + +## 现实案例 + +* [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) +* [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) +* [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) +* [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) +* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (Returns different singleton objects, depending on a protocol) +* [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E)) +* [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) and other similar methods. + +## 相关模式 + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/) +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) + diff --git a/zh/sharding/README.md b/zh/sharding/README.md new file mode 100644 index 000000000..b4b6073e0 --- /dev/null +++ b/zh/sharding/README.md @@ -0,0 +1,30 @@ +--- +layout: pattern +title: Sharding +folder: sharding +permalink: /patterns/sharding/ +categories: Behavioral +tags: + - Performance + - Cloud distributed +--- + +## 含义 +分片模式是指将数据存储划分为水平分区或分片。每个分片都有相同的模式,但持有自己独特的数据子集。 + +一个分片本身就是一个数据存储(它可以包含许多不同类型的实体的数据),运行在作为存储节点的服务器上。 + +## 类图 +![alt text](../../sharding/etc/sharding.urm.png "Sharding pattern class diagram") + +## 适用场景 +这种设计模式提供了一下的好处: + +- 你可以通过增加在额外的存储节点上,运行的更多分片来实现系统扩容。 +- 系统可以使用现成的廉价硬件,而不是为每个存储节点使用专门(或者昂贵)的服务器硬件。 +- 你可以通过平衡各分片之间的工作负载来减少竞争,以提高性能。 +- 在云环境中,分片可以在物理上靠近访问该节点数据的用户。 + +## 引用 + +* [Sharding pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/sharding) \ No newline at end of file