Compare commits
9 Commits
all-contri
...
all-contri
Author | SHA1 | Date | |
---|---|---|---|
|
8645415679 | ||
|
9909215414 | ||
|
14c4710435 | ||
|
428cbc1027 | ||
|
a118a995ec | ||
|
759c99d078 | ||
|
e9f73bcf0b | ||
|
29ceac2fb0 | ||
|
7255c2c5e7 |
@@ -1296,6 +1296,33 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"doc"
|
"doc"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "omk13",
|
||||||
|
"name": "Omar Karazoun",
|
||||||
|
"avatar_url": "https://avatars0.githubusercontent.com/u/59054172?v=4",
|
||||||
|
"profile": "https://github.com/omk13",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "jeff303",
|
||||||
|
"name": "Jeff Evans",
|
||||||
|
"avatar_url": "https://avatars0.githubusercontent.com/u/3521562?v=4",
|
||||||
|
"profile": "https://github.com/jeff303",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "viveksb007",
|
||||||
|
"name": "Vivek Singh",
|
||||||
|
"avatar_url": "https://avatars1.githubusercontent.com/u/12713808?v=4",
|
||||||
|
"profile": "https://viveksb007.github.io",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 4,
|
"contributorsPerLine": 4,
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||||
[](#contributors-)
|
[](#contributors-)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
@@ -282,6 +282,11 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<tr>
|
<tr>
|
||||||
<td align="center"><a href="https://ibrahimalii.github.io/"><img src="https://avatars2.githubusercontent.com/u/21141301?v=4" width="100px;" alt=""/><br /><sub><b>Ibrahim ali abdelghany</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AibrahimAlii" title="Reviewed Pull Requests">👀</a></td>
|
<td align="center"><a href="https://ibrahimalii.github.io/"><img src="https://avatars2.githubusercontent.com/u/21141301?v=4" width="100px;" alt=""/><br /><sub><b>Ibrahim ali abdelghany</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AibrahimAlii" title="Reviewed Pull Requests">👀</a></td>
|
||||||
<td align="center"><a href="https://github.com/gkulkarni2020"><img src="https://avatars3.githubusercontent.com/u/5161548?v=4" width="100px;" alt=""/><br /><sub><b>Girish Kulkarni</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gkulkarni2020" title="Documentation">📖</a></td>
|
<td align="center"><a href="https://github.com/gkulkarni2020"><img src="https://avatars3.githubusercontent.com/u/5161548?v=4" width="100px;" alt=""/><br /><sub><b>Girish Kulkarni</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gkulkarni2020" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/omk13"><img src="https://avatars0.githubusercontent.com/u/59054172?v=4" width="100px;" alt=""/><br /><sub><b>Omar Karazoun</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=omk13" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/jeff303"><img src="https://avatars0.githubusercontent.com/u/3521562?v=4" width="100px;" alt=""/><br /><sub><b>Jeff Evans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jeff303" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://viveksb007.github.io"><img src="https://avatars1.githubusercontent.com/u/12713808?v=4" width="100px;" alt=""/><br /><sub><b>Vivek Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=viveksb007" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -98,7 +98,7 @@ Now on the client code we can create different types of cars using the factory c
|
|||||||
var car1 = CarsFactory.getCar(CarType.FORD);
|
var car1 = CarsFactory.getCar(CarType.FORD);
|
||||||
var car2 = CarsFactory.getCar(CarType.FERRARI);
|
var car2 = CarsFactory.getCar(CarType.FERRARI);
|
||||||
LOGGER.info(car1.getDescription());
|
LOGGER.info(car1.getDescription());
|
||||||
LOGGER.info(car2.getDescription());;
|
LOGGER.info(car2.getDescription());
|
||||||
```
|
```
|
||||||
|
|
||||||
Program output:
|
Program output:
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
package com.iluwatar.gameloop;
|
package com.iluwatar.gameloop;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
|
@@ -23,10 +23,11 @@
|
|||||||
|
|
||||||
package com.iluwatar.gameloop;
|
package com.iluwatar.gameloop;
|
||||||
|
|
||||||
import org.junit.After;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FixedStepGameLoop unit test class.
|
* FixedStepGameLoop unit test class.
|
||||||
@@ -35,12 +36,12 @@ public class FixedStepGameLoopTest {
|
|||||||
|
|
||||||
private FixedStepGameLoop gameLoop;
|
private FixedStepGameLoop gameLoop;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
gameLoop = new FixedStepGameLoop();
|
gameLoop = new FixedStepGameLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@AfterEach
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
gameLoop = null;
|
gameLoop = null;
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,7 @@ public class FixedStepGameLoopTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdate() {
|
public void testUpdate() {
|
||||||
gameLoop.update();
|
gameLoop.update();
|
||||||
Assert.assertEquals(0.01f, gameLoop.controller.getBulletPosition(), 0);
|
assertEquals(0.01f, gameLoop.controller.getBulletPosition(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -23,10 +23,10 @@
|
|||||||
|
|
||||||
package com.iluwatar.gameloop;
|
package com.iluwatar.gameloop;
|
||||||
|
|
||||||
import org.junit.After;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FrameBasedGameLoop unit test class.
|
* FrameBasedGameLoop unit test class.
|
||||||
@@ -35,19 +35,19 @@ public class FrameBasedGameLoopTest {
|
|||||||
|
|
||||||
private FrameBasedGameLoop gameLoop;
|
private FrameBasedGameLoop gameLoop;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
gameLoop = new FrameBasedGameLoop();
|
gameLoop = new FrameBasedGameLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@AfterEach
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
gameLoop = null;
|
gameLoop = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@org.junit.jupiter.api.Test
|
||||||
public void testUpdate() {
|
public void testUpdate() {
|
||||||
gameLoop.update();
|
gameLoop.update();
|
||||||
Assert.assertEquals(0.5f, gameLoop.controller.getBulletPosition(), 0);
|
assertEquals(0.5f, gameLoop.controller.getBulletPosition(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,34 +23,33 @@
|
|||||||
|
|
||||||
package com.iluwatar.gameloop;
|
package com.iluwatar.gameloop;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class GameControllerTest {
|
public class GameControllerTest {
|
||||||
|
|
||||||
private GameController controller;
|
private GameController controller;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
controller = new GameController();
|
controller = new GameController();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@AfterEach
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
controller = null;
|
controller = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@org.junit.jupiter.api.Test
|
||||||
public void testMoveBullet() {
|
public void testMoveBullet() {
|
||||||
controller.moveBullet(1.5f);
|
controller.moveBullet(1.5f);
|
||||||
Assert.assertEquals(1.5f, controller.bullet.getPosition(), 0);
|
Assertions.assertEquals(1.5f, controller.bullet.getPosition(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@org.junit.jupiter.api.Test
|
||||||
public void testGetBulletPosition() {
|
public void testGetBulletPosition() {
|
||||||
Assert.assertEquals(controller.bullet.getPosition(), controller.getBulletPosition(), 0);
|
Assertions.assertEquals(controller.bullet.getPosition(), controller.getBulletPosition(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -23,10 +23,9 @@
|
|||||||
|
|
||||||
package com.iluwatar.gameloop;
|
package com.iluwatar.gameloop;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GameLoop unit test class.
|
* GameLoop unit test class.
|
||||||
@@ -38,7 +37,7 @@ public class GameLoopTest {
|
|||||||
/**
|
/**
|
||||||
* Create mock implementation of GameLoop.
|
* Create mock implementation of GameLoop.
|
||||||
*/
|
*/
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
gameLoop = new GameLoop() {
|
gameLoop = new GameLoop() {
|
||||||
@Override
|
@Override
|
||||||
@@ -46,26 +45,26 @@ public class GameLoopTest {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@AfterEach
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
gameLoop = null;
|
gameLoop = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@org.junit.jupiter.api.Test
|
||||||
public void testRun() {
|
public void testRun() {
|
||||||
gameLoop.run();
|
gameLoop.run();
|
||||||
Assert.assertEquals(GameStatus.RUNNING, gameLoop.status);
|
Assertions.assertEquals(GameStatus.RUNNING, gameLoop.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@org.junit.jupiter.api.Test
|
||||||
public void testStop() {
|
public void testStop() {
|
||||||
gameLoop.stop();
|
gameLoop.stop();
|
||||||
Assert.assertEquals(GameStatus.STOPPED, gameLoop.status);
|
Assertions.assertEquals(GameStatus.STOPPED, gameLoop.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@org.junit.jupiter.api.Test
|
||||||
public void testIsGameRunning() {
|
public void testIsGameRunning() {
|
||||||
Assert.assertFalse(gameLoop.isGameRunning());
|
Assertions.assertFalse(gameLoop.isGameRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -23,11 +23,9 @@
|
|||||||
|
|
||||||
package com.iluwatar.gameloop;
|
package com.iluwatar.gameloop;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.After;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VariableStepGameLoop unit test class.
|
* VariableStepGameLoop unit test class.
|
||||||
@@ -36,19 +34,19 @@ public class VariableStepGameLoopTest {
|
|||||||
|
|
||||||
private VariableStepGameLoop gameLoop;
|
private VariableStepGameLoop gameLoop;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
gameLoop = new VariableStepGameLoop();
|
gameLoop = new VariableStepGameLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@AfterEach
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
gameLoop = null;
|
gameLoop = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@org.junit.jupiter.api.Test
|
||||||
public void testUpdate() {
|
public void testUpdate() {
|
||||||
gameLoop.update(20L);
|
gameLoop.update(20L);
|
||||||
Assert.assertEquals(0.01f, gameLoop.controller.getBulletPosition(), 0);
|
Assertions.assertEquals(0.01f, gameLoop.controller.getBulletPosition(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
pom.xml
1
pom.xml
@@ -195,6 +195,7 @@
|
|||||||
<module>strangler</module>
|
<module>strangler</module>
|
||||||
<module>arrange-act-assert</module>
|
<module>arrange-act-assert</module>
|
||||||
<module>transaction-script</module>
|
<module>transaction-script</module>
|
||||||
|
<module>registry</module>
|
||||||
<module>filterer</module>
|
<module>filterer</module>
|
||||||
<module>factory</module>
|
<module>factory</module>
|
||||||
<module>separated-interface</module>
|
<module>separated-interface</module>
|
||||||
|
86
registry/README.md
Normal file
86
registry/README.md
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
layout: pattern
|
||||||
|
title: Registry
|
||||||
|
folder: registry
|
||||||
|
permalink: /patterns/registry/
|
||||||
|
categories: Creational
|
||||||
|
tags:
|
||||||
|
- Instantiation
|
||||||
|
---
|
||||||
|
|
||||||
|
## Intent
|
||||||
|
Stores the objects of a single class and provide a global point of access to them.
|
||||||
|
Similar to Multiton pattern, only difference is that in a registry there is no restriction on the number of objects.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
In Plain Words
|
||||||
|
|
||||||
|
> Registry is a well-known object that other objects can use to find common objects and services.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
Below is a `Customer` Class
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class Customer {
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public Customer(String id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This registry of the `Customer` objects is `CustomerRegistry`
|
||||||
|
```java
|
||||||
|
public final class CustomerRegistry {
|
||||||
|
|
||||||
|
private static final CustomerRegistry instance = new CustomerRegistry();
|
||||||
|
|
||||||
|
public static CustomerRegistry getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Customer> customerMap;
|
||||||
|
|
||||||
|
private CustomerRegistry() {
|
||||||
|
customerMap = new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer addCustomer(Customer customer) {
|
||||||
|
return customerMap.put(customer.getId(), customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer getCustomer(String id) {
|
||||||
|
return customerMap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|

|
||||||
|
|
||||||
|
## Applicability
|
||||||
|
Use Registry pattern when
|
||||||
|
|
||||||
|
* client wants reference of some object, so client can lookup for that object in the object's registry.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
Large number of bulky objects added to registry would result in a lot of memory consumption as objects in the registry are not garbage collected.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
* https://www.martinfowler.com/eaaCatalog/registry.html
|
||||||
|
* https://wiki.c2.com/?RegistryPattern
|
BIN
registry/etc/registry.png
Normal file
BIN
registry/etc/registry.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
21
registry/etc/registry.urm.puml
Normal file
21
registry/etc/registry.urm.puml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.registry {
|
||||||
|
class App {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ App()
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
}
|
||||||
|
class Customer {
|
||||||
|
- id : String
|
||||||
|
- name : String
|
||||||
|
+ getId() : String
|
||||||
|
+ getName() : String
|
||||||
|
+ toString() : String
|
||||||
|
}
|
||||||
|
class CustomerRegistry {
|
||||||
|
+ addCustomer(customer : Customer)
|
||||||
|
+ getCustomer(id : String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Customer --> "-addCustomer" CustomerRegistry
|
||||||
|
@enduml
|
46
registry/pom.xml
Normal file
46
registry/pom.xml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.iluwatar</groupId>
|
||||||
|
<artifactId>java-design-patterns</artifactId>
|
||||||
|
<version>1.24.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>registry</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.registry.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
27
registry/src/main/java/com/iluwatar/registry/App.java
Normal file
27
registry/src/main/java/com/iluwatar/registry/App.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package com.iluwatar.registry;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
CustomerRegistry customerRegistry = CustomerRegistry.getInstance();
|
||||||
|
var john = new Customer("1", "John");
|
||||||
|
customerRegistry.addCustomer(john);
|
||||||
|
|
||||||
|
var julia = new Customer("2", "Julia");
|
||||||
|
customerRegistry.addCustomer(julia);
|
||||||
|
|
||||||
|
LOGGER.info("John {}", customerRegistry.getCustomer("1"));
|
||||||
|
LOGGER.info("Julia {}", customerRegistry.getCustomer("2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
registry/src/main/java/com/iluwatar/registry/Customer.java
Normal file
28
registry/src/main/java/com/iluwatar/registry/Customer.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package com.iluwatar.registry;
|
||||||
|
|
||||||
|
public class Customer {
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public Customer(String id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Customer{"
|
||||||
|
+ "id='" + id + '\''
|
||||||
|
+ ", name='" + name + '\''
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
package com.iluwatar.registry;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public final class CustomerRegistry {
|
||||||
|
|
||||||
|
private static final CustomerRegistry instance = new CustomerRegistry();
|
||||||
|
|
||||||
|
public static CustomerRegistry getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Customer> customerMap;
|
||||||
|
|
||||||
|
private CustomerRegistry() {
|
||||||
|
customerMap = new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer addCustomer(Customer customer) {
|
||||||
|
return customerMap.put(customer.getId(), customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer getCustomer(String id) {
|
||||||
|
return customerMap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
package com.iluwatar.registry;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
public class CustomerRegistryTest {
|
||||||
|
|
||||||
|
private static CustomerRegistry customerRegistry;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void setUp() {
|
||||||
|
customerRegistry = CustomerRegistry.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldBeAbleToAddAndQueryCustomerObjectFromRegistry() {
|
||||||
|
Customer john = new Customer("1", "john");
|
||||||
|
Customer julia = new Customer("2", "julia");
|
||||||
|
|
||||||
|
customerRegistry.addCustomer(john);
|
||||||
|
customerRegistry.addCustomer(julia);
|
||||||
|
|
||||||
|
Customer customerWithId1 = customerRegistry.getCustomer("1");
|
||||||
|
assertNotNull(customerWithId1);
|
||||||
|
assertEquals("1", customerWithId1.getId());
|
||||||
|
assertEquals("john", customerWithId1.getName());
|
||||||
|
|
||||||
|
Customer customerWithId2 = customerRegistry.getCustomer("2");
|
||||||
|
assertNotNull(customerWithId2);
|
||||||
|
assertEquals("2", customerWithId2.getId());
|
||||||
|
assertEquals("julia", customerWithId2.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnNullWhenQueriedCustomerIsNotInRegistry() {
|
||||||
|
Customer customerWithId5 = customerRegistry.getCustomer("5");
|
||||||
|
assertNull(customerWithId5);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
205
zh/bridge/README.md
Normal file
205
zh/bridge/README.md
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
---
|
||||||
|
layout: pattern
|
||||||
|
title: Bridge
|
||||||
|
folder: bridge
|
||||||
|
permalink: /patterns/bridge/
|
||||||
|
categories: Structural
|
||||||
|
tags:
|
||||||
|
- Gang of Four
|
||||||
|
---
|
||||||
|
|
||||||
|
## 又被称为
|
||||||
|
|
||||||
|
手柄/身体模式
|
||||||
|
|
||||||
|
## 目的
|
||||||
|
|
||||||
|
将抽象与其实现分离,以便二者可以独立变化。
|
||||||
|
|
||||||
|
## 解释
|
||||||
|
|
||||||
|
真实世界例子
|
||||||
|
|
||||||
|
> 考虑一下你拥有一种具有不同附魔的武器,并且应该允许将具有不同附魔的不同武器混合使用。 你会怎么做? 为每个附魔创建每种武器的多个副本,还是只是创建单独的附魔并根据需要为武器设置它? 桥接模式使您可以进行第二次操作。
|
||||||
|
|
||||||
|
通俗的说
|
||||||
|
|
||||||
|
> 桥接模式是一个更推荐组合而不是继承的模式。将实现细节从一个层次结构推送到具有单独层次结构的另一个对象。
|
||||||
|
|
||||||
|
维基百科说
|
||||||
|
|
||||||
|
> 桥接模式是软件工程中使用的一种设计模式,旨在“将抽象与其实现分离,从而使两者可以独立变化”
|
||||||
|
|
||||||
|
**程序示例**
|
||||||
|
|
||||||
|
翻译一下上面的武器示例。下面我们有武器的类层级:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface Weapon {
|
||||||
|
void wield();
|
||||||
|
void swing();
|
||||||
|
void unwield();
|
||||||
|
Enchantment getEnchantment();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Sword implements Weapon {
|
||||||
|
|
||||||
|
private final Enchantment enchantment;
|
||||||
|
|
||||||
|
public Sword(Enchantment enchantment) {
|
||||||
|
this.enchantment = enchantment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void wield() {
|
||||||
|
LOGGER.info("The sword is wielded.");
|
||||||
|
enchantment.onActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void swing() {
|
||||||
|
LOGGER.info("The sword is swinged.");
|
||||||
|
enchantment.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unwield() {
|
||||||
|
LOGGER.info("The sword is unwielded.");
|
||||||
|
enchantment.onDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enchantment getEnchantment() {
|
||||||
|
return enchantment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Hammer implements Weapon {
|
||||||
|
|
||||||
|
private final Enchantment enchantment;
|
||||||
|
|
||||||
|
public Hammer(Enchantment enchantment) {
|
||||||
|
this.enchantment = enchantment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void wield() {
|
||||||
|
LOGGER.info("The hammer is wielded.");
|
||||||
|
enchantment.onActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void swing() {
|
||||||
|
LOGGER.info("The hammer is swinged.");
|
||||||
|
enchantment.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unwield() {
|
||||||
|
LOGGER.info("The hammer is unwielded.");
|
||||||
|
enchantment.onDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enchantment getEnchantment() {
|
||||||
|
return enchantment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这里是单独的附魔类结构:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface Enchantment {
|
||||||
|
void onActivate();
|
||||||
|
void apply();
|
||||||
|
void onDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FlyingEnchantment implements Enchantment {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivate() {
|
||||||
|
LOGGER.info("The item begins to glow faintly.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply() {
|
||||||
|
LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeactivate() {
|
||||||
|
LOGGER.info("The item's glow fades.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SoulEatingEnchantment implements Enchantment {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivate() {
|
||||||
|
LOGGER.info("The item spreads bloodlust.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply() {
|
||||||
|
LOGGER.info("The item eats the soul of enemies.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeactivate() {
|
||||||
|
LOGGER.info("Bloodlust slowly disappears.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这里是两种层次结构的实践:
|
||||||
|
|
||||||
|
```java
|
||||||
|
var enchantedSword = new Sword(new SoulEatingEnchantment());
|
||||||
|
enchantedSword.wield();
|
||||||
|
enchantedSword.swing();
|
||||||
|
enchantedSword.unwield();
|
||||||
|
// The sword is wielded.
|
||||||
|
// The item spreads bloodlust.
|
||||||
|
// The sword is swinged.
|
||||||
|
// The item eats the soul of enemies.
|
||||||
|
// The sword is unwielded.
|
||||||
|
// Bloodlust slowly disappears.
|
||||||
|
|
||||||
|
var hammer = new Hammer(new FlyingEnchantment());
|
||||||
|
hammer.wield();
|
||||||
|
hammer.swing();
|
||||||
|
hammer.unwield();
|
||||||
|
// The hammer is wielded.
|
||||||
|
// The item begins to glow faintly.
|
||||||
|
// The hammer is swinged.
|
||||||
|
// The item flies and strikes the enemies finally returning to owner's hand.
|
||||||
|
// The hammer is unwielded.
|
||||||
|
// The item's glow fades.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 类图
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 适用性
|
||||||
|
|
||||||
|
使用桥接模式当
|
||||||
|
|
||||||
|
* 你想永久性的避免抽象和他的实现之间的绑定。有可能是这种情况,当实现需要被选择或者在运行时切换。
|
||||||
|
* 抽象和他们的实现应该能通过写子类来扩展。这种情况下,桥接模式让你可以组合不同的抽象和实现并独立的扩展他们。
|
||||||
|
* 对抽象的实现的改动应当不会对客户产生影响;也就是说,他们的代码不必重新编译。
|
||||||
|
* 你有种类繁多的类。这样的类层次结构表明需要将一个对象分为两部分。Rumbaugh 使用术语“嵌套归纳”来指代这种类层次结构。
|
||||||
|
* 你想在多个对象间分享一种实现(可能使用引用计数),这个事实应该对客户隐藏。一个简单的示例是Coplien的String类,其中多个对象可以共享同一字符串表示形式
|
||||||
|
|
||||||
|
## 教程
|
||||||
|
|
||||||
|
* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java)
|
||||||
|
|
||||||
|
## 鸣谢
|
||||||
|
|
||||||
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||||
|
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
@@ -33,8 +33,6 @@ tags:
|
|||||||
|
|
||||||
以巨魔的为例。首先我有有一个简单的巨魔,实现了巨魔接口。
|
以巨魔的为例。首先我有有一个简单的巨魔,实现了巨魔接口。
|
||||||
|
|
||||||
程序mple. First of all we have a simple troll implementing the troll interface
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Troll {
|
public interface Troll {
|
||||||
void attack();
|
void attack();
|
||||||
|
101
zh/dependency-injection/README.md
Normal file
101
zh/dependency-injection/README.md
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
---
|
||||||
|
layout: pattern
|
||||||
|
title: Dependency Injection
|
||||||
|
folder: dependency-injection
|
||||||
|
permalink: /patterns/dependency-injection/
|
||||||
|
categories: Creational
|
||||||
|
tags:
|
||||||
|
- Decoupling
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目的
|
||||||
|
|
||||||
|
依赖注入是一种软件设计模式,其中一个或多个依赖项(或服务)被注入或通过引用传递到一个依赖对象(或客户端)中,并成为客户端状态的一部分。该模式将客户的依赖关系的创建与其自身的行为分开,这使程序设计可以松散耦合,并遵循控制反转和单一职责原则。
|
||||||
|
|
||||||
|
## 解释
|
||||||
|
|
||||||
|
真实世界例子
|
||||||
|
|
||||||
|
> 老巫师喜欢不时地装满烟斗抽烟。 但是,他不想只依赖一个烟草品牌,而是希望能够互换使用它们。
|
||||||
|
|
||||||
|
通俗的说
|
||||||
|
|
||||||
|
> 依赖注入将客户端依赖的创建与其自身行为分开。
|
||||||
|
|
||||||
|
维基百科说
|
||||||
|
|
||||||
|
> 在软件工程中,依赖注入是一种对象接收其依赖的其他对象的技术。 这些其他对象称为依赖项。
|
||||||
|
|
||||||
|
**程序示例**
|
||||||
|
|
||||||
|
先介绍一下烟草接口和具体的品牌。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public abstract class Tobacco {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class);
|
||||||
|
|
||||||
|
public void smoke(Wizard wizard) {
|
||||||
|
LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(),
|
||||||
|
this.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SecondBreakfastTobacco extends Tobacco {
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RivendellTobacco extends Tobacco {
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OldTobyTobacco extends Tobacco {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
下面是老巫师的类的层次结构。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface Wizard {
|
||||||
|
|
||||||
|
void smoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AdvancedWizard implements Wizard {
|
||||||
|
|
||||||
|
private final Tobacco tobacco;
|
||||||
|
|
||||||
|
public AdvancedWizard(Tobacco tobacco) {
|
||||||
|
this.tobacco = tobacco;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void smoke() {
|
||||||
|
tobacco.smoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
最后我们可以看到给老巫师任意品牌的烟草是多么的简单。
|
||||||
|
|
||||||
|
```java
|
||||||
|
var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
|
||||||
|
advancedWizard.smoke();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 类图
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 适用性
|
||||||
|
|
||||||
|
使用依赖注入当:
|
||||||
|
|
||||||
|
- 当你需要从对象中移除掉具体的实现内容时
|
||||||
|
|
||||||
|
* 使用模拟对象或存根隔离地启用类的单元测试
|
||||||
|
|
||||||
|
## 鸣谢
|
||||||
|
|
||||||
|
* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd)
|
||||||
|
* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871)
|
||||||
|
* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1)
|
||||||
|
* [Google Guice Tutorial: Open source Java based dependency injection framework](https://www.amazon.com/gp/product/B083P7DZ8M/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B083P7DZ8M&linkId=04f0f902c877921e45215b624a124bfe)
|
Reference in New Issue
Block a user