Compare commits
4 Commits
all-contri
...
code-clean
Author | SHA1 | Date | |
---|---|---|---|
fdab5318f3 | |||
a68edf0f3d | |||
0f35681674 | |||
981985531d |
@ -1038,61 +1038,6 @@
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "charlesfinley",
|
||||
"name": "Matt Dolan",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/6307904?v=4",
|
||||
"profile": "https://github.com/charlesfinley",
|
||||
"contributions": [
|
||||
"code",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "MananS77",
|
||||
"name": "Manan",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/21033516?v=4",
|
||||
"profile": "https://github.com/MananS77",
|
||||
"contributions": [
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nishant",
|
||||
"name": "Nishant Arora",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/15331971?v=4",
|
||||
"profile": "https://github.com/nishant",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "raja-peeyush-kumar-singh",
|
||||
"name": "Peeyush",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/5496024?v=4",
|
||||
"profile": "https://github.com/raja-peeyush-kumar-singh",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ravening",
|
||||
"name": "Rakesh",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/10645273?v=4",
|
||||
"profile": "https://github.com/ravening",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "vINCENT8888801",
|
||||
"name": "Wei Seng",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/8037883?v=4",
|
||||
"profile": "https://github.com/vINCENT8888801",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 4,
|
||||
|
10
README.md
10
README.md
@ -9,7 +9,7 @@
|
||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
# Introduction
|
||||
@ -239,14 +239,6 @@ This project is licensed under the terms of the MIT license.
|
||||
<tr>
|
||||
<td align="center"><a href="https://webpro.nl"><img src="https://avatars1.githubusercontent.com/u/456426?v=4" width="100px;" alt=""/><br /><sub><b>Lars Kappert</b></sub></a><br /><a href="#content-webpro" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://xiaod.info"><img src="https://avatars2.githubusercontent.com/u/21277644?v=4" width="100px;" alt=""/><br /><sub><b>Mike Liu</b></sub></a><br /><a href="#translation-xiaod-dev" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Acharlesfinley" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/MananS77"><img src="https://avatars3.githubusercontent.com/u/21033516?v=4" width="100px;" alt=""/><br /><sub><b>Manan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AMananS77" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nishant"><img src="https://avatars2.githubusercontent.com/u/15331971?v=4" width="100px;" alt=""/><br /><sub><b>Nishant Arora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nishant" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/raja-peeyush-kumar-singh"><img src="https://avatars0.githubusercontent.com/u/5496024?v=4" width="100px;" alt=""/><br /><sub><b>Peeyush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=raja-peeyush-kumar-singh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vINCENT8888801"><img src="https://avatars0.githubusercontent.com/u/8037883?v=4" width="100px;" alt=""/><br /><sub><b>Wei Seng</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vINCENT8888801" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -9,182 +9,21 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Use dynamic properties and achieve flexibility of untyped languages while keeping type-safety.
|
||||
|
||||
## Explanation
|
||||
|
||||
The Abstract Document pattern enables handling additional, non-static properties. This pattern
|
||||
uses concept of traits to enable type safety and separate properties of different classes into
|
||||
set of interfaces.
|
||||
|
||||
Real world example
|
||||
|
||||
> Consider a car that consists of multiple parts. However we don't know if the specific car really has all the parts, or just some of them. Our cars are dynamic and extremely flexible.
|
||||
|
||||
In plain words
|
||||
|
||||
> Abstract Document pattern allows attaching properties to objects without them knowing about it.
|
||||
|
||||
Wikipedia says
|
||||
|
||||
> An object-oriented structural design pattern for organizing objects in loosely typed key-value stores and exposing
|
||||
the data using typed views. The purpose of the pattern is to achieve a high degree of flexibility between components
|
||||
in a strongly typed language where new properties can be added to the object-tree on the fly, without losing the
|
||||
support of type-safety. The pattern makes use of traits to separate different properties of a class into different
|
||||
interfaces.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Let's first define the base classes `Document` and `AbstractDocument`. They basically make the object hold a property
|
||||
map and any amount of child objects.
|
||||
|
||||
```java
|
||||
public interface Document {
|
||||
|
||||
Void put(String key, Object value);
|
||||
|
||||
Object get(String key);
|
||||
|
||||
<T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
|
||||
}
|
||||
|
||||
public abstract class AbstractDocument implements Document {
|
||||
|
||||
private final Map<String, Object> properties;
|
||||
|
||||
protected AbstractDocument(Map<String, Object> properties) {
|
||||
Objects.requireNonNull(properties, "properties map is required");
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void put(String key, Object value) {
|
||||
properties.put(key, value);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String key) {
|
||||
return properties.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
|
||||
return Stream.ofNullable(get(key))
|
||||
.filter(Objects::nonNull)
|
||||
.map(el -> (List<Map<String, Object>>) el)
|
||||
.findAny()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.map(constructor);
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
Next we define an enum `Property` and a set of interfaces for type, price, model and parts. This allows us to create
|
||||
static looking interface to our `Car` class.
|
||||
|
||||
```java
|
||||
public enum Property {
|
||||
|
||||
PARTS, TYPE, PRICE, MODEL
|
||||
}
|
||||
|
||||
public interface HasType extends Document {
|
||||
|
||||
default Optional<String> getType() {
|
||||
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public interface HasPrice extends Document {
|
||||
|
||||
default Optional<Number> getPrice() {
|
||||
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
||||
}
|
||||
}
|
||||
public interface HasModel extends Document {
|
||||
|
||||
default Optional<String> getModel() {
|
||||
return Optional.ofNullable((String) get(Property.MODEL.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public interface HasParts extends Document {
|
||||
|
||||
default Stream<Part> getParts() {
|
||||
return children(Property.PARTS.toString(), Part::new);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now we are ready to introduce the `Car`.
|
||||
|
||||
```java
|
||||
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
|
||||
|
||||
public Car(Map<String, Object> properties) {
|
||||
super(properties);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And finally here's how we construct and use the `Car` in a full example.
|
||||
|
||||
```java
|
||||
LOGGER.info("Constructing parts and car");
|
||||
|
||||
var wheelProperties = Map.of(
|
||||
Property.TYPE.toString(), "wheel",
|
||||
Property.MODEL.toString(), "15C",
|
||||
Property.PRICE.toString(), 100L);
|
||||
|
||||
var doorProperties = Map.of(
|
||||
Property.TYPE.toString(), "door",
|
||||
Property.MODEL.toString(), "Lambo",
|
||||
Property.PRICE.toString(), 300L);
|
||||
|
||||
var carProperties = Map.of(
|
||||
Property.MODEL.toString(), "300SL",
|
||||
Property.PRICE.toString(), 10000L,
|
||||
Property.PARTS.toString(), List.of(wheelProperties, doorProperties));
|
||||
|
||||
var car = new Car(carProperties);
|
||||
|
||||
LOGGER.info("Here is our car:");
|
||||
LOGGER.info("-> model: {}", car.getModel().orElseThrow());
|
||||
LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
|
||||
LOGGER.info("-> parts: ");
|
||||
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}",
|
||||
p.getType().orElse(null),
|
||||
p.getModel().orElse(null),
|
||||
p.getPrice().orElse(null))
|
||||
);
|
||||
|
||||
// Constructing parts and car
|
||||
// Here is our car:
|
||||
// model: 300SL
|
||||
// price: 10000
|
||||
// parts:
|
||||
// wheel/15C/100
|
||||
// door/Lambo/300
|
||||
```
|
||||
Achieve flexibility of untyped languages and keep the type-safety
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
## Applicability
|
||||
Use the Abstract Document Pattern when
|
||||
|
||||
* There is a need to add new properties on the fly
|
||||
* You want a flexible way to organize domain in tree like structure
|
||||
* You want more loosely coupled system
|
||||
* there is a need to add new properties on the fly
|
||||
* you want a flexible way to organize domain in tree like structure
|
||||
* you want more loosely coupled system
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
|
||||
* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
|
||||
* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)](https://www.amazon.com/gp/product/0470059028/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0470059028&linkId=e3aacaea7017258acf184f9f3283b492)
|
||||
|
@ -43,11 +43,9 @@ public class App {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
* Executes the App.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
public App() {
|
||||
LOGGER.info("Constructing parts and car");
|
||||
|
||||
var wheelProperties = Map.of(
|
||||
@ -77,4 +75,14 @@ public class App {
|
||||
p.getPrice().orElse(null))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new App();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
public interface HasParts extends Document {
|
||||
|
||||
|
||||
default Stream<Part> getParts() {
|
||||
return children(Property.PARTS.toString(), Part::new);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import java.util.Optional;
|
||||
*/
|
||||
public interface HasPrice extends Document {
|
||||
|
||||
|
||||
default Optional<Number> getPrice() {
|
||||
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import java.util.Optional;
|
||||
*/
|
||||
public interface HasType extends Document {
|
||||
|
||||
|
||||
default Optional<String> getType() {
|
||||
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.abstractdocument {
|
||||
requires org.slf4j;
|
||||
}
|
@ -40,7 +40,7 @@ public class AbstractDocumentTest {
|
||||
private static final String KEY = "key";
|
||||
private static final String VALUE = "value";
|
||||
|
||||
private static class DocumentImplementation extends AbstractDocument {
|
||||
private class DocumentImplementation extends AbstractDocument {
|
||||
|
||||
DocumentImplementation(Map<String, Object> properties) {
|
||||
super(properties);
|
||||
|
@ -9,19 +9,16 @@ tags:
|
||||
---
|
||||
|
||||
## Also known as
|
||||
|
||||
Kit
|
||||
|
||||
## Intent
|
||||
|
||||
Provide an interface for creating families of related or dependent
|
||||
objects without specifying their concrete classes.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> To create a kingdom we need objects with a common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
|
||||
> To create a kingdom we need objects with common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
|
||||
|
||||
In plain words
|
||||
|
||||
@ -33,18 +30,15 @@ Wikipedia says
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the
|
||||
kingdom.
|
||||
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the kingdom
|
||||
|
||||
```java
|
||||
public interface Castle {
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
public interface King {
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
public interface Army {
|
||||
String getDescription();
|
||||
}
|
||||
@ -72,7 +66,7 @@ public class ElfArmy implements Army {
|
||||
}
|
||||
}
|
||||
|
||||
// Orcish implementations similarly -> ...
|
||||
// Orcish implementations similarly...
|
||||
|
||||
```
|
||||
|
||||
@ -118,17 +112,9 @@ var castle = factory.createCastle();
|
||||
var king = factory.createKing();
|
||||
var army = factory.createArmy();
|
||||
|
||||
castle.getDescription();
|
||||
king.getDescription();
|
||||
army.getDescription();
|
||||
```
|
||||
|
||||
Program output:
|
||||
|
||||
```java
|
||||
This is the Elven castle!
|
||||
This is the Elven king!
|
||||
This is the Elven Army!
|
||||
castle.getDescription(); // Output: This is the Elven castle!
|
||||
king.getDescription(); // Output: This is the Elven king!
|
||||
army.getDescription(); // Output: This is the Elven Army!
|
||||
```
|
||||
|
||||
Now, we can design a factory for our different kingdom factories. In this example, we created FactoryMaker, responsible for returning an instance of either ElfKingdomFactory or OrcKingdomFactory.
|
||||
@ -170,52 +156,46 @@ public static void main(String[] args) {
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
|
||||
## Applicability
|
||||
|
||||
Use the Abstract Factory pattern when
|
||||
|
||||
* The system should be independent of how its products are created, composed and represented
|
||||
* The system should be configured with one of multiple families of products
|
||||
* The family of related product objects is designed to be used together, and you need to enforce this constraint
|
||||
* You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
|
||||
* The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
|
||||
* You need a run-time value to construct a particular dependency
|
||||
* You want to decide which product to call from a family at runtime.
|
||||
* You need to supply one or more parameters only known at run-time before you can resolve a dependency.
|
||||
* When you need consistency among products
|
||||
* You don’t want to change existing code when adding new products or families of products to the program.
|
||||
* a system should be independent of how its products are created, composed and represented
|
||||
* a system should be configured with one of multiple families of products
|
||||
* a family of related product objects is designed to be used together, and you need to enforce this constraint
|
||||
* you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
|
||||
* the lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
|
||||
* you need a run-time value to construct a particular dependency
|
||||
* you want to decide which product to call from a family at runtime.
|
||||
* you need to supply one or more parameters only known at run-time before you can resolve a dependency.
|
||||
* when you need consistency among products
|
||||
* you don’t want to change existing code when adding new products or families of products to the program.
|
||||
|
||||
Example use cases
|
||||
## Use Cases:
|
||||
|
||||
* Selecting to call to the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
|
||||
* Unit test case writing becomes much easier
|
||||
* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
|
||||
* Unit test case writing becomes much easier
|
||||
* UI tools for different OS
|
||||
|
||||
## Consequences:
|
||||
|
||||
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
|
||||
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
|
||||
* While the pattern is great when creating predefined objects, adding the new ones might be challenging.
|
||||
* The code becomes more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
|
||||
* The code may become more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
|
||||
|
||||
|
||||
## Tutorial
|
||||
|
||||
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
||||
|
||||
## Known uses
|
||||
|
||||
## Real world examples
|
||||
|
||||
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
||||
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
|
||||
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
|
||||
|
||||
## Related patterns
|
||||
|
||||
[Factory Method](https://java-design-patterns.com/patterns/factory-method/)
|
||||
[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [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)
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.abstractfactory {
|
||||
requires org.slf4j;
|
||||
}
|
@ -9,126 +9,12 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating
|
||||
the troublesome dependency cycles that are inherent to the GoF Visitor Pattern.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> We have a hierarchy of modem classes. The modems in this hierarchy need to be visited by an external algorithm based
|
||||
> on filtering criteria (is it Unix or DOS compatible modem).
|
||||
|
||||
In plain words
|
||||
|
||||
> Acyclic Visitor allows functions to be added to existing class hierarchies without modifying the hierarchies.
|
||||
|
||||
[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) says
|
||||
|
||||
> The Acyclic Visitor pattern allows new functions to be added to existing class hierarchies without affecting those
|
||||
> hierarchies, and without creating the dependency cycles that are inherent to the GangOfFour VisitorPattern.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Here's the `Modem` hierarchy.
|
||||
|
||||
```java
|
||||
public abstract class Modem {
|
||||
public abstract void accept(ModemVisitor modemVisitor);
|
||||
}
|
||||
|
||||
public class Zoom extends Modem {
|
||||
...
|
||||
@Override
|
||||
public void accept(ModemVisitor modemVisitor) {
|
||||
if (modemVisitor instanceof ZoomVisitor) {
|
||||
((ZoomVisitor) modemVisitor).visit(this);
|
||||
} else {
|
||||
LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Hayes extends Modem {
|
||||
...
|
||||
@Override
|
||||
public void accept(ModemVisitor modemVisitor) {
|
||||
if (modemVisitor instanceof HayesVisitor) {
|
||||
((HayesVisitor) modemVisitor).visit(this);
|
||||
} else {
|
||||
LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Next we introduce the `ModemVisitor` hierarchy.
|
||||
|
||||
```java
|
||||
public interface ModemVisitor {
|
||||
}
|
||||
|
||||
public interface HayesVisitor extends ModemVisitor {
|
||||
void visit(Hayes hayes);
|
||||
}
|
||||
|
||||
public interface ZoomVisitor extends ModemVisitor {
|
||||
void visit(Zoom zoom);
|
||||
}
|
||||
|
||||
public interface AllModemVisitor extends ZoomVisitor, HayesVisitor {
|
||||
}
|
||||
|
||||
public class ConfigureForDosVisitor implements AllModemVisitor {
|
||||
...
|
||||
@Override
|
||||
public void visit(Hayes hayes) {
|
||||
LOGGER.info(hayes + " used with Dos configurator.");
|
||||
}
|
||||
@Override
|
||||
public void visit(Zoom zoom) {
|
||||
LOGGER.info(zoom + " used with Dos configurator.");
|
||||
}
|
||||
}
|
||||
|
||||
public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||
...
|
||||
@Override
|
||||
public void visit(Zoom zoom) {
|
||||
LOGGER.info(zoom + " used with Unix configurator.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, here are the visitors in action.
|
||||
|
||||
```java
|
||||
var conUnix = new ConfigureForUnixVisitor();
|
||||
var conDos = new ConfigureForDosVisitor();
|
||||
var zoom = new Zoom();
|
||||
var hayes = new Hayes();
|
||||
hayes.accept(conDos);
|
||||
zoom.accept(conDos);
|
||||
hayes.accept(conUnix);
|
||||
zoom.accept(conUnix);
|
||||
```
|
||||
|
||||
Program output:
|
||||
|
||||
```
|
||||
// Hayes modem used with Dos configurator.
|
||||
// Zoom modem used with Dos configurator.
|
||||
// Only HayesVisitor is allowed to visit Hayes modem
|
||||
// Zoom modem used with Unix configurator.
|
||||
```
|
||||
Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating the troublesome dependency cycles that are inherent to the GOF VISITOR Pattern.
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
This pattern can be used:
|
||||
|
||||
* When you need to add a new function to an existing hierarchy without the need to alter or affect that hierarchy.
|
||||
@ -138,7 +24,6 @@ This pattern can be used:
|
||||
* When the recompilation, relinking, retesting or redistribution of the derivatives of Element is very expensive.
|
||||
|
||||
## Consequences
|
||||
|
||||
The good:
|
||||
|
||||
* No dependency cycles between class hierarchies.
|
||||
@ -147,14 +32,11 @@ The good:
|
||||
|
||||
The bad:
|
||||
|
||||
* Violates [Liskov's Substitution Principle](https://java-design-patterns.com/principles/#liskov-substitution-principle) by showing that it can accept all visitors but actually only being interested in particular visitors.
|
||||
* Violates the principle of least surprise or Liskov's Substitution principle by showing that it can accept all visitors but actually only being interested in particular visitors.
|
||||
* Parallel hierarchy of visitors has to be created for all members in visitable class hierarchy.
|
||||
|
||||
## Related patterns
|
||||
|
||||
* [Visitor Pattern](https://java-design-patterns.com/patterns/visitor/)
|
||||
* [Visitor Pattern](../visitor/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
|
||||
* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor)
|
||||
* [Acyclic Visitor](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
|
||||
|
115
acyclic-visitor/etc/Acyclic Visitor.ucls
Normal file
115
acyclic-visitor/etc/Acyclic Visitor.ucls
Normal file
@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
||||
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
||||
<interface id="1" language="java" name="com.iluwatar.acyclicvisitor.ModemVisitor" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ModemVisitor.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="860" y="67"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</interface>
|
||||
<class id="2" language="java" name="com.iluwatar.acyclicvisitor.Modem" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Modem.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="327" y="77"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="3" language="java" name="com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitor.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="124" width="196" x="647" y="225"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="4" language="java" name="com.iluwatar.acyclicvisitor.Zoom" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Zoom.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="203" y="305"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<interface id="5" language="java" name="com.iluwatar.acyclicvisitor.HayesVisitor" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/HayesVisitor.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="1019" y="468"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</interface>
|
||||
<interface id="6" language="java" name="com.iluwatar.acyclicvisitor.ZoomVisitor" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ZoomVisitor.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="758" y="467"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</interface>
|
||||
<class id="7" language="java" name="com.iluwatar.acyclicvisitor.Hayes" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Hayes.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="479" y="307"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="8" language="java" name="com.iluwatar.acyclicvisitor.ConfigureForDosVisitor" project="acyclic-visitor"
|
||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitor.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="142" width="192" x="883" y="225"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<generalization id="9">
|
||||
<end type="SOURCE" refId="7"/>
|
||||
<end type="TARGET" refId="2"/>
|
||||
</generalization>
|
||||
<realization id="10">
|
||||
<end type="SOURCE" refId="8"/>
|
||||
<end type="TARGET" refId="6"/>
|
||||
</realization>
|
||||
<realization id="11">
|
||||
<end type="SOURCE" refId="8"/>
|
||||
<end type="TARGET" refId="5"/>
|
||||
</realization>
|
||||
<realization id="12">
|
||||
<end type="SOURCE" refId="3"/>
|
||||
<end type="TARGET" refId="6"/>
|
||||
</realization>
|
||||
<realization id="13">
|
||||
<end type="SOURCE" refId="3"/>
|
||||
<end type="TARGET" refId="1"/>
|
||||
</realization>
|
||||
<realization id="14">
|
||||
<end type="SOURCE" refId="8"/>
|
||||
<end type="TARGET" refId="1"/>
|
||||
</realization>
|
||||
<generalization id="15">
|
||||
<end type="SOURCE" refId="4"/>
|
||||
<end type="TARGET" refId="2"/>
|
||||
</generalization>
|
||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</classifier-display>
|
||||
<association-display labels="true" multiplicity="true"/>
|
||||
</class-diagram>
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 26 KiB |
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.acyclicvisitor {
|
||||
requires org.slf4j;
|
||||
}
|
@ -12,8 +12,9 @@ tags:
|
||||
Wrapper
|
||||
|
||||
## Intent
|
||||
Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that
|
||||
couldn't otherwise because of incompatible interfaces.
|
||||
Convert the interface of a class into another interface the clients
|
||||
expect. Adapter lets classes work together that couldn't otherwise because of
|
||||
incompatible interfaces.
|
||||
|
||||
## Explanation
|
||||
|
||||
|
@ -10,91 +10,16 @@ tags:
|
||||
|
||||
## Intent
|
||||
|
||||
The user makes a single call to the aggregator service, and the aggregator then calls each relevant microservice.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> Our web marketplace needs information about products and their current inventory. It makes a call to an aggregator
|
||||
> service which in turn calls the product information microservice and product inventory microservice returning the
|
||||
> combined information.
|
||||
|
||||
In plain words
|
||||
|
||||
> Aggregator Microservice collects pieces of data from various microservices and returns an aggregate for processing.
|
||||
|
||||
Stack Overflow says
|
||||
|
||||
> Aggregator Microservice invokes multiple services to achieve the functionality required by the application.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Let's start from the data model. Here's our `Product`.
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private String title;
|
||||
private int productInventories;
|
||||
// getters and setters ->
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Next we can introduce our `Aggregator` microservice. It contains clients `ProductInformationClient` and
|
||||
`ProductInventoryClient` for calling respective microservices.
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class Aggregator {
|
||||
|
||||
@Resource
|
||||
private ProductInformationClient informationClient;
|
||||
|
||||
@Resource
|
||||
private ProductInventoryClient inventoryClient;
|
||||
|
||||
@RequestMapping(path = "/product", method = RequestMethod.GET)
|
||||
public Product getProduct() {
|
||||
|
||||
var product = new Product();
|
||||
var productTitle = informationClient.getProductTitle();
|
||||
var productInventory = inventoryClient.getProductInventories();
|
||||
|
||||
//Fallback to error message
|
||||
product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed"));
|
||||
|
||||
//Fallback to default error inventory
|
||||
product.setProductInventories(requireNonNullElse(productInventory, -1));
|
||||
|
||||
return product;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here's the essence of information microservice implementation. Inventory microservice is similar, it just returns
|
||||
inventory counts.
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class InformationController {
|
||||
@RequestMapping(value = "/information", method = RequestMethod.GET)
|
||||
public String getProductTitle() {
|
||||
return "The Product Title.";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now calling our `Aggregator` REST API returns the product information.
|
||||
|
||||
```bash
|
||||
curl http://localhost:50004/product
|
||||
{"title":"The Product Title.","productInventories":5}
|
||||
```
|
||||
The user makes a single call to the Aggregator, and the aggregator then calls each relevant microservice and collects
|
||||
the data, apply business logic to it, and further publish is as a REST Endpoint.
|
||||
More variations of the aggregator are:
|
||||
- Proxy Microservice Design Pattern: A different microservice is called upon the business need.
|
||||
- Chained Microservice Design Pattern: In this case each microservice is dependent/ chained to a series
|
||||
of other microservices.
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
@ -103,5 +28,3 @@ Use the Aggregator Microservices pattern when you need a unified API for various
|
||||
## Credits
|
||||
|
||||
* [Microservice Design Patterns](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/)
|
||||
* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60)
|
||||
* [Architectural Patterns: Uncover essential patterns in the most indispensable realm of enterprise architecture](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4)
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 40 KiB |
BIN
aggregator-microservices/etc/aggregator-microservice.png
Normal file
BIN
aggregator-microservices/etc/aggregator-microservice.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
@ -10,37 +10,28 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Provide a helper service instance on a client and offload common functionality away from a shared resource.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> A remote service has many clients accessing a function it provides. The service is a legacy application and is
|
||||
> impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request
|
||||
> frequency should be implemented along with latency checks and client-side logging.
|
||||
> A remote service has many clients accessing a function it provides. The service is a legacy application and is impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request frequency should be implemented along with latency checks and client-side logging.
|
||||
|
||||
In plain words
|
||||
|
||||
> With the Ambassador pattern, we can implement less-frequent polling from clients along with latency checks and
|
||||
> logging.
|
||||
> Using the ambassador pattern, we can implement less-frequent polling from clients along with latency checks and logging.
|
||||
|
||||
Microsoft documentation states
|
||||
|
||||
> An ambassador service can be thought of as an out-of-process proxy which is co-located with the client. This pattern
|
||||
> can be useful for offloading common client connectivity tasks such as monitoring, logging, routing,
|
||||
> security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications,
|
||||
> or other applications that are difficult to modify, in order to extend their networking capabilities. It can also
|
||||
> enable a specialized team to implement those features.
|
||||
> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client. This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
With the above introduction in mind we will imitate the functionality in this example. We have an interface implemented
|
||||
by the remote service as well as the ambassador service:
|
||||
With the above example in mind we will imitate the functionality in a simple manner. We have an interface implemented by the remote service as well as the ambassador service:
|
||||
|
||||
```java
|
||||
interface RemoteServiceInterface {
|
||||
|
||||
long doRemoteFunction(int value) throws Exception;
|
||||
}
|
||||
```
|
||||
@ -145,7 +136,7 @@ public class Client {
|
||||
}
|
||||
```
|
||||
|
||||
Here are two clients using the service.
|
||||
And here are two clients using the service.
|
||||
|
||||
```java
|
||||
public class App {
|
||||
@ -158,29 +149,13 @@ public class App {
|
||||
}
|
||||
```
|
||||
|
||||
Here's the output for running the example:
|
||||
|
||||
```java
|
||||
Time taken (ms): 111
|
||||
Service result: 120
|
||||
Time taken (ms): 931
|
||||
Failed to reach remote: (1)
|
||||
Time taken (ms): 665
|
||||
Failed to reach remote: (2)
|
||||
Time taken (ms): 538
|
||||
Failed to reach remote: (3)
|
||||
Service result: -1
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
Ambassador is applicable when working with a legacy remote service which cannot be modified or would be extremely
|
||||
difficult to modify. Connectivity features can be implemented on the client avoiding the need for changes on the remote
|
||||
service.
|
||||
Ambassador is applicable when working with a legacy remote service that cannot
|
||||
be modified or would be extremely difficult to modify. Connectivity features can
|
||||
be implemented on the client avoiding the need for changes on the remote service.
|
||||
|
||||
* Ambassador provides a local interface for a remote service.
|
||||
* Ambassador provides logging, circuit breaking, retries and security on the client.
|
||||
@ -193,14 +168,10 @@ service.
|
||||
* Offload remote service tasks
|
||||
* Facilitate network connection
|
||||
|
||||
## Known uses
|
||||
## Real world examples
|
||||
|
||||
* [Kubernetes-native API gateway for microservices](https://github.com/datawire/ambassador)
|
||||
|
||||
## Related patterns
|
||||
|
||||
* [Proxy](https://java-design-patterns.com/patterns/proxy/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Ambassador pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador)
|
||||
|
@ -29,5 +29,5 @@ package com.iluwatar.ambassador;
|
||||
interface RemoteServiceInterface {
|
||||
int FAILURE = -1;
|
||||
|
||||
long doRemoteFunction(int value);
|
||||
long doRemoteFunction(int value) throws Exception;
|
||||
}
|
||||
|
@ -9,137 +9,22 @@ tags:
|
||||
---
|
||||
|
||||
## Also known as
|
||||
|
||||
Given/When/Then
|
||||
|
||||
## Intent
|
||||
|
||||
Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
|
||||
The Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
|
||||
It breaks tests down into three clear and distinct steps:
|
||||
|
||||
1. Arrange: Perform the setup and initialization required for the test.
|
||||
2. Act: Take action(s) required for the test.
|
||||
3. Assert: Verify the outcome(s) of the test.
|
||||
|
||||
## Explanation
|
||||
|
||||
This pattern has several significant benefits. It creates a clear separation between a test's
|
||||
setup, operations, and results. This structure makes the code easier to read and understand. If
|
||||
you place the steps in order and format your code to separate them, you can scan a test and
|
||||
quickly comprehend what it does.
|
||||
|
||||
It also enforces a certain degree of discipline when you write your tests. You have to think
|
||||
clearly about the three steps your test will perform. It makes tests more natural to write at
|
||||
the same time since you already have an outline.
|
||||
|
||||
Real world example
|
||||
|
||||
> We need to write comprehensive and clear unit test suite for a class.
|
||||
|
||||
In plain words
|
||||
|
||||
> Arrange/Act/Assert is a testing pattern that organizes tests into three clear steps for easy
|
||||
> maintenance.
|
||||
|
||||
WikiWikiWeb says
|
||||
|
||||
> Arrange/Act/Assert is a pattern for arranging and formatting code in UnitTest methods.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Let's first introduce our `Cash` class to be unit tested.
|
||||
|
||||
```java
|
||||
public class Cash {
|
||||
|
||||
private int amount;
|
||||
|
||||
Cash(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
void plus(int addend) {
|
||||
amount += addend;
|
||||
}
|
||||
|
||||
boolean minus(int subtrahend) {
|
||||
if (amount >= subtrahend) {
|
||||
amount -= subtrahend;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int count() {
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the clearly
|
||||
separated steps for each unit test.
|
||||
|
||||
```java
|
||||
public class CashAAATest {
|
||||
|
||||
@Test
|
||||
public void testPlus() {
|
||||
//Arrange
|
||||
var cash = new Cash(3);
|
||||
//Act
|
||||
cash.plus(4);
|
||||
//Assert
|
||||
assertEquals(7, cash.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(8);
|
||||
//Act
|
||||
var result = cash.minus(5);
|
||||
//Assert
|
||||
assertTrue(result);
|
||||
assertEquals(3, cash.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsufficientMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(1);
|
||||
//Act
|
||||
var result = cash.minus(6);
|
||||
//Assert
|
||||
assertFalse(result);
|
||||
assertEquals(1, cash.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
//Arrange
|
||||
var cash = new Cash(5);
|
||||
//Act
|
||||
cash.plus(6);
|
||||
var result = cash.minus(3);
|
||||
//Assert
|
||||
assertTrue(result);
|
||||
assertEquals(8, cash.count());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Applicability
|
||||
|
||||
Use Arrange/Act/Assert pattern when
|
||||
|
||||
* You need to structure your unit tests so that they're easier to read, maintain, and enhance.
|
||||
* you need to structure your unit tests so they're easier to read, maintain, and enhance.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Arrange, Act, Assert: What is AAA Testing?](https://blog.ncrunch.net/post/arrange-act-assert-aaa-testing.aspx)
|
||||
* [Bill Wake: 3A – Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/)
|
||||
* [Martin Fowler: GivenWhenThen](https://martinfowler.com/bliki/GivenWhenThen.html)
|
||||
* [xUnit Test Patterns: Refactoring Test Code](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f7e8dd50d720c9b63dbf)
|
||||
* [Unit Testing Principles, Practices, and Patterns](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cf22a63c3e4758ae08aa0a0cc35)
|
||||
* [Test Driven Development: By Example](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b84ca5087472ef0e05)
|
||||
|
@ -60,7 +60,7 @@ public class CashAAATest {
|
||||
//Act
|
||||
cash.plus(4);
|
||||
//Assert
|
||||
assertEquals(7, cash.count());
|
||||
assertEquals(cash.count(), 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -71,7 +71,7 @@ public class CashAAATest {
|
||||
var result = cash.minus(5);
|
||||
//Assert
|
||||
assertTrue(result);
|
||||
assertEquals(3, cash.count());
|
||||
assertEquals(cash.count(), 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -82,7 +82,7 @@ public class CashAAATest {
|
||||
var result = cash.minus(6);
|
||||
//Assert
|
||||
assertFalse(result);
|
||||
assertEquals(1, cash.count());
|
||||
assertEquals(cash.count(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -94,6 +94,6 @@ public class CashAAATest {
|
||||
var result = cash.minus(3);
|
||||
//Assert
|
||||
assertTrue(result);
|
||||
assertEquals(8, cash.count());
|
||||
assertEquals(cash.count(), 8);
|
||||
}
|
||||
}
|
||||
|
@ -44,16 +44,16 @@ public class CashAntiAAATest {
|
||||
var cash = new Cash(3);
|
||||
//test plus
|
||||
cash.plus(4);
|
||||
assertEquals(7, cash.count());
|
||||
assertEquals(cash.count(), 7);
|
||||
//test minus
|
||||
cash = new Cash(8);
|
||||
assertTrue(cash.minus(5));
|
||||
assertEquals(3, cash.count());
|
||||
assertEquals(cash.count(), 3);
|
||||
assertFalse(cash.minus(6));
|
||||
assertEquals(3, cash.count());
|
||||
assertEquals(cash.count(), 3);
|
||||
//test update
|
||||
cash.plus(5);
|
||||
assertTrue(cash.minus(5));
|
||||
assertEquals(3, cash.count());
|
||||
assertEquals(cash.count(), 3);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.business.delegate {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.callback {
|
||||
requires org.slf4j;
|
||||
}
|
26
chain/src/main/java/com/iluwatar/chain/module-info.java
Normal file
26
chain/src/main/java/com/iluwatar/chain/module-info.java
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.chain {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.collectionpipeline {
|
||||
requires org.slf4j;
|
||||
}
|
@ -75,18 +75,19 @@ public class Wizard {
|
||||
Next we present the spell hierarchy.
|
||||
|
||||
```java
|
||||
public interface Command {
|
||||
public abstract class Command {
|
||||
|
||||
void execute(Target target);
|
||||
public abstract void execute(Target target);
|
||||
|
||||
void undo();
|
||||
public abstract void undo();
|
||||
|
||||
void redo();
|
||||
public abstract void redo();
|
||||
|
||||
String toString();
|
||||
@Override
|
||||
public abstract String toString();
|
||||
}
|
||||
|
||||
public class InvisibilitySpell implements Command {
|
||||
public class InvisibilitySpell extends Command {
|
||||
|
||||
private Target target;
|
||||
|
||||
@ -116,7 +117,7 @@ public class InvisibilitySpell implements Command {
|
||||
}
|
||||
}
|
||||
|
||||
public class ShrinkSpell implements Command {
|
||||
public class ShrinkSpell extends Command {
|
||||
|
||||
private Size oldSize;
|
||||
private Target target;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 27 KiB |
@ -4,7 +4,7 @@ package com.iluwatar.command {
|
||||
+ App()
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
interface Command {
|
||||
abstract class Command {
|
||||
+ Command()
|
||||
+ execute(Target) {abstract}
|
||||
+ redo() {abstract}
|
||||
@ -77,7 +77,7 @@ ShrinkSpell --> "-oldSize" Size
|
||||
InvisibilitySpell --> "-target" Target
|
||||
ShrinkSpell --> "-target" Target
|
||||
Target --> "-visibility" Visibility
|
||||
Goblin --|> Target
|
||||
InvisibilitySpell ..|> Command
|
||||
ShrinkSpell ..|> Command
|
||||
@enduml
|
||||
Goblin --|> Target
|
||||
InvisibilitySpell --|> Command
|
||||
ShrinkSpell --|> Command
|
||||
@enduml
|
@ -26,12 +26,15 @@ package com.iluwatar.command;
|
||||
/**
|
||||
* Interface for Commands.
|
||||
*/
|
||||
public interface Command {
|
||||
void execute(Target target);
|
||||
public abstract class Command {
|
||||
|
||||
void undo();
|
||||
public abstract void execute(Target target);
|
||||
|
||||
void redo();
|
||||
public abstract void undo();
|
||||
|
||||
public abstract void redo();
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
String toString();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ package com.iluwatar.command;
|
||||
/**
|
||||
* InvisibilitySpell is a concrete command.
|
||||
*/
|
||||
public class InvisibilitySpell implements Command {
|
||||
public class InvisibilitySpell extends Command {
|
||||
|
||||
private Target target;
|
||||
|
||||
|
@ -26,7 +26,7 @@ package com.iluwatar.command;
|
||||
/**
|
||||
* ShrinkSpell is a concrete command.
|
||||
*/
|
||||
public class ShrinkSpell implements Command {
|
||||
public class ShrinkSpell extends Command {
|
||||
|
||||
private Size oldSize;
|
||||
private Target target;
|
||||
|
26
command/src/main/java/com/iluwatar/command/module-info.java
Normal file
26
command/src/main/java/com/iluwatar/command/module-info.java
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.command {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.composite {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.converter {
|
||||
requires org.slf4j;
|
||||
}
|
29
dao/src/main/java/com/iluwatar/dao/module-info.java
Normal file
29
dao/src/main/java/com/iluwatar/dao/module-info.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.dao {
|
||||
requires org.slf4j;
|
||||
requires java.sql;
|
||||
requires h2;
|
||||
requires java.naming;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.datamapper {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.datatransfer {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.decorator {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.delegation {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.dirtyflag {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.doublecheckedlocking {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.doubledispatch {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.eipmessagechannel {
|
||||
requires org.slf4j;
|
||||
requires camel.core;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.eippublishsubscribe {
|
||||
requires org.slf4j;
|
||||
requires camel.core;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.eventaggregator {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.eventasynchronous {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.executearound {
|
||||
requires org.slf4j;
|
||||
}
|
26
facade/src/main/java/com/iluwatar/facade/module-info.java
Normal file
26
facade/src/main/java/com/iluwatar/facade/module-info.java
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.facade {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.factorykit {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.factorymethod {
|
||||
requires org.slf4j;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2019 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module com.iluwatar.featuretoggle {
|
||||
requires org.slf4j;
|
||||
}
|
@ -46,18 +46,17 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final var logger = LoggerFactory.getLogger(App.class);
|
||||
var guard = new Guard();
|
||||
var thief = new Thief();
|
||||
|
||||
//noinspection ConstantConditions
|
||||
final Logger logger = LoggerFactory.getLogger(App.class);
|
||||
Guard guard = new Guard();
|
||||
Thief thief = new Thief();
|
||||
|
||||
if (guard instanceof Permission) {
|
||||
guard.enter();
|
||||
} else {
|
||||
logger.info("You have no permission to enter, please leave this area");
|
||||
}
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (thief instanceof Permission) {
|
||||
thief.steal();
|
||||
} else {
|
||||
|
@ -28,9 +28,11 @@ import org.slf4j.LoggerFactory;
|
||||
* Class defining Guard.
|
||||
*/
|
||||
public class Guard implements Permission {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Guard.class);
|
||||
|
||||
protected void enter() {
|
||||
protected static void enter() {
|
||||
|
||||
LOGGER.info("You can enter");
|
||||
}
|
||||
}
|
||||
|
@ -28,13 +28,14 @@ import org.slf4j.LoggerFactory;
|
||||
* Class defining Thief.
|
||||
*/
|
||||
public class Thief {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Thief.class);
|
||||
|
||||
protected void steal() {
|
||||
protected static void steal() {
|
||||
LOGGER.info("Steal valuable items");
|
||||
}
|
||||
|
||||
protected void doNothing() {
|
||||
protected static void doNothing() {
|
||||
LOGGER.info("Pretend nothing happened and just leave");
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
App.main(new String[]{});
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public class GuardTest {
|
||||
|
||||
@Test
|
||||
public void testGuard() {
|
||||
var guard = new Guard();
|
||||
Guard guard = new Guard();
|
||||
assertThat(guard, instanceOf(Permission.class));
|
||||
}
|
||||
}
|
@ -21,19 +21,17 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
/**
|
||||
* Thief test
|
||||
*/
|
||||
public class ThiefTest {
|
||||
@Test
|
||||
public void testThief() {
|
||||
var thief = new Thief();
|
||||
assertThat(thief, not(instanceOf(Permission.class)));
|
||||
Thief thief = new Thief();
|
||||
assertFalse(thief instanceof Permission);
|
||||
}
|
||||
}
|
@ -22,39 +22,38 @@
|
||||
THE SOFTWARE.
|
||||
|
||||
-->
|
||||
<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.23.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>master-worker-pattern</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<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.23.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>master-worker-pattern</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.masterworker.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.masterworker.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@ -34,25 +34,27 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>The <b><em>Master-Worker</em></b> pattern is used when the problem at hand can be solved by
|
||||
* dividing into multiple parts which need to go through the same computation and may need to be
|
||||
* aggregated to get final result. Parallel processing is performed using a system consisting of a
|
||||
* master and some number of workers, where a master divides the work among the workers, gets the
|
||||
* result back from them and assimilates all the results to give final result. The only
|
||||
* communication is between the master and the worker - none of the workers communicate among one
|
||||
* another and the user only communicates with the master to get required job done.</p>
|
||||
* dividing into
|
||||
* multiple parts which need to go through the same computation and may need to be aggregated to get
|
||||
* final result. Parallel processing is performed using a system consisting of a master and some
|
||||
* number of workers, where a master divides the work among the workers, gets the result back from
|
||||
* them and assimilates all the results to give final result. The only communication is between the
|
||||
* master and the worker - none of the workers communicate among one another and the user only
|
||||
* communicates with the master to get required job done.</p>
|
||||
* <p>In our example, we have generic abstract classes {@link MasterWorker}, {@link Master} and
|
||||
* {@link Worker} which have to be extended by the classes which will perform the specific job at
|
||||
* hand (in this case finding transpose of matrix, done by {@link ArrayTransposeMasterWorker},
|
||||
* {@link ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work
|
||||
* into parts to be given to the workers, collects the results from the workers and aggregates it
|
||||
* when all workers have responded before returning the solution. The Worker class extends the
|
||||
* Thread class to enable parallel processing, and does the work once the data has been received
|
||||
* from the Master. The MasterWorker contains a reference to the Master class, gets the input from
|
||||
* the App and passes it on to the Master. These 3 classes define the system which computes the
|
||||
* result. We also have 2 abstract classes {@link Input} and {@link Result}, which contain the input
|
||||
* data and result data respectively. The Input class also has an abstract method divideData which
|
||||
* defines how the data is to be divided into segments. These classes are extended by {@link
|
||||
* ArrayInput} and {@link ArrayResult}.</p>
|
||||
* {@link Worker} which
|
||||
* have to be extended by the classes which will perform the specific job at hand (in this case
|
||||
* finding transpose of matrix, done by {@link ArrayTransposeMasterWorker}, {@link
|
||||
* ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work into
|
||||
* parts to be given to the workers, collects the results from the workers and aggregates it when
|
||||
* all workers have responded before returning the solution. The Worker class extends the Thread
|
||||
* class to enable parallel processing, and does the work once the data has been received from the
|
||||
* Master. The MasterWorker contains a reference to the Master class, gets the input from the App
|
||||
* and passes it on to the Master. These 3 classes define the system which computes the result. We
|
||||
* also have 2 abstract classes {@link Input} and {@link Result}, which contain the input data and
|
||||
* result data respectively. The Input class also has an abstract method divideData which defines
|
||||
* how the data is to be divided into segments. These classes are extended by {@link ArrayInput} and
|
||||
* {@link ArrayResult}.</p>
|
||||
*/
|
||||
|
||||
public class App {
|
||||
@ -66,12 +68,12 @@ public class App {
|
||||
*/
|
||||
|
||||
public static void main(String[] args) {
|
||||
var mw = new ArrayTransposeMasterWorker();
|
||||
var rows = 10;
|
||||
var columns = 20;
|
||||
var inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
|
||||
var input = new ArrayInput(inputMatrix);
|
||||
var result = (ArrayResult) mw.getResult(input);
|
||||
ArrayTransposeMasterWorker mw = new ArrayTransposeMasterWorker();
|
||||
int rows = 10;
|
||||
int columns = 20;
|
||||
int[][] inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
|
||||
ArrayInput input = new ArrayInput(inputMatrix);
|
||||
ArrayResult result = (ArrayResult) mw.getResult(input);
|
||||
if (result != null) {
|
||||
ArrayUtilityMethods.printMatrix(inputMatrix);
|
||||
ArrayUtilityMethods.printMatrix(result.data);
|
||||
|
@ -25,7 +25,6 @@ package com.iluwatar.masterworker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class ArrayInput extends abstract class {@link Input} and contains data of type int[][].
|
||||
@ -38,12 +37,12 @@ public class ArrayInput extends Input<int[][]> {
|
||||
}
|
||||
|
||||
static int[] makeDivisions(int[][] data, int num) {
|
||||
var initialDivision = data.length / num; //equally dividing
|
||||
var divisions = new int[num];
|
||||
int initialDivision = data.length / num; //equally dividing
|
||||
int[] divisions = new int[num];
|
||||
Arrays.fill(divisions, initialDivision);
|
||||
if (initialDivision * num != data.length) {
|
||||
var extra = data.length - initialDivision * num;
|
||||
var l = 0;
|
||||
int extra = data.length - initialDivision * num;
|
||||
int l = 0;
|
||||
//equally dividing extra among all parts
|
||||
while (extra > 0) {
|
||||
divisions[l] = divisions[l] + 1;
|
||||
@ -59,20 +58,22 @@ public class ArrayInput extends Input<int[][]> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Input<int[][]>> divideData(int num) {
|
||||
public ArrayList<Input> divideData(int num) {
|
||||
if (this.data == null) {
|
||||
return null;
|
||||
} else {
|
||||
var divisions = makeDivisions(this.data, num);
|
||||
var result = new ArrayList<Input<int[][]>>(num);
|
||||
var rowsDone = 0; //number of rows divided so far
|
||||
for (var i = 0; i < num; i++) {
|
||||
var rows = divisions[i];
|
||||
int[] divisions = makeDivisions(this.data, num);
|
||||
ArrayList<Input> result = new ArrayList<Input>(num);
|
||||
int rowsDone = 0; //number of rows divided so far
|
||||
for (int i = 0; i < num; i++) {
|
||||
int rows = divisions[i];
|
||||
if (rows != 0) {
|
||||
var divided = new int[rows][this.data[0].length];
|
||||
System.arraycopy(this.data, rowsDone, divided, 0, rows);
|
||||
int[][] divided = new int[rows][this.data[0].length];
|
||||
for (int j = 0; j < rows; j++) {
|
||||
divided[j] = this.data[rowsDone + j];
|
||||
}
|
||||
rowsDone += rows;
|
||||
var dividedInput = new ArrayInput(divided);
|
||||
ArrayInput dividedInput = new ArrayInput(divided);
|
||||
result.add(dividedInput);
|
||||
} else {
|
||||
break; //rest of divisions will also be 0
|
||||
|
@ -47,8 +47,8 @@ public class ArrayUtilityMethods {
|
||||
if (a1.length != a2.length) {
|
||||
return false;
|
||||
} else {
|
||||
var answer = false;
|
||||
for (var i = 0; i < a1.length; i++) {
|
||||
boolean answer = false;
|
||||
for (int i = 0; i < a1.length; i++) {
|
||||
if (a1[i] == a2[i]) {
|
||||
answer = true;
|
||||
} else {
|
||||
@ -69,8 +69,8 @@ public class ArrayUtilityMethods {
|
||||
if (m1.length != m2.length) {
|
||||
return false;
|
||||
} else {
|
||||
var answer = false;
|
||||
for (var i = 0; i < m1.length; i++) {
|
||||
boolean answer = false;
|
||||
for (int i = 0; i < m1.length; i++) {
|
||||
if (arraysSame(m1[i], m2[i])) {
|
||||
answer = true;
|
||||
} else {
|
||||
@ -88,9 +88,9 @@ public class ArrayUtilityMethods {
|
||||
* @return it (int[][]).
|
||||
*/
|
||||
public static int[][] createRandomIntMatrix(int rows, int columns) {
|
||||
var matrix = new int[rows][columns];
|
||||
for (var i = 0; i < rows; i++) {
|
||||
for (var j = 0; j < columns; j++) {
|
||||
int[][] matrix = new int[rows][columns];
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
//filling cells in matrix
|
||||
matrix[i][j] = RANDOM.nextInt(10);
|
||||
}
|
||||
@ -104,9 +104,9 @@ public class ArrayUtilityMethods {
|
||||
|
||||
public static void printMatrix(int[][] matrix) {
|
||||
//prints out int[][]
|
||||
for (var ints : matrix) {
|
||||
for (var j = 0; j < matrix[0].length; j++) {
|
||||
LOGGER.info(ints[j] + " ");
|
||||
for (int i = 0; i < matrix.length; i++) {
|
||||
for (int j = 0; j < matrix[0].length; j++) {
|
||||
LOGGER.info(matrix[i][j] + " ");
|
||||
}
|
||||
LOGGER.info("");
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
package com.iluwatar.masterworker;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The abstract Input class, having 1 public field which contains input data, and abstract method
|
||||
@ -40,5 +40,5 @@ public abstract class Input<T> {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public abstract List<Input<T>> divideData(int num);
|
||||
public abstract ArrayList<Input> divideData(int num);
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ public abstract class MasterWorker {
|
||||
|
||||
abstract Master setMaster(int numOfWorkers);
|
||||
|
||||
public Result<?> getResult(Input<?> input) {
|
||||
public Result getResult(Input input) {
|
||||
this.master.doWork(input);
|
||||
return this.master.getFinalResult();
|
||||
}
|
||||
|
@ -27,8 +27,7 @@ import com.iluwatar.masterworker.ArrayResult;
|
||||
import com.iluwatar.masterworker.system.systemworkers.ArrayTransposeWorker;
|
||||
import com.iluwatar.masterworker.system.systemworkers.Worker;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Class ArrayTransposeMaster extends abstract class {@link Master} and contains definition of
|
||||
@ -42,33 +41,35 @@ public class ArrayTransposeMaster extends Master {
|
||||
|
||||
@Override
|
||||
ArrayList<Worker> setWorkers(int num) {
|
||||
//i+1 will be id
|
||||
return IntStream.range(0, num)
|
||||
.mapToObj(i -> new ArrayTransposeWorker(this, i + 1))
|
||||
.collect(Collectors.toCollection(() -> new ArrayList<>(num)));
|
||||
ArrayList<Worker> ws = new ArrayList<Worker>(num);
|
||||
for (int i = 0; i < num; i++) {
|
||||
ws.add(new ArrayTransposeWorker(this, i + 1));
|
||||
//i+1 will be id
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
|
||||
@Override
|
||||
ArrayResult aggregateData() {
|
||||
// number of rows in final result is number of rows in any of obtained results from workers
|
||||
var allResultData = this.getAllResultData();
|
||||
var rows = ((ArrayResult) allResultData.elements().nextElement()).data.length;
|
||||
var elements = allResultData.elements();
|
||||
var columns = 0; // columns = sum of number of columns in all results obtained from workers
|
||||
while (elements.hasMoreElements()) {
|
||||
columns += ((ArrayResult) elements.nextElement()).data[0].length;
|
||||
int rows = ((ArrayResult) this.getAllResultData()
|
||||
.get(this.getAllResultData().keys().nextElement())).data.length;
|
||||
int columns =
|
||||
0; //number of columns is sum of number of columns in all results obtained from workers
|
||||
for (Enumeration<Integer> e = this.getAllResultData().keys(); e.hasMoreElements(); ) {
|
||||
columns += ((ArrayResult) this.getAllResultData().get(e.nextElement())).data[0].length;
|
||||
}
|
||||
var resultData = new int[rows][columns];
|
||||
var columnsDone = 0; //columns aggregated so far
|
||||
var workers = this.getWorkers();
|
||||
for (var i = 0; i < this.getExpectedNumResults(); i++) {
|
||||
int[][] resultData = new int[rows][columns];
|
||||
int columnsDone = 0; //columns aggregated so far
|
||||
for (int i = 0; i < this.getExpectedNumResults(); i++) {
|
||||
//result obtained from ith worker
|
||||
var worker = workers.get(i);
|
||||
var workerId = worker.getWorkerId();
|
||||
var work = ((ArrayResult) allResultData.get(workerId)).data;
|
||||
for (var m = 0; m < work.length; m++) {
|
||||
int[][] work =
|
||||
((ArrayResult) this.getAllResultData().get(this.getWorkers().get(i).getWorkerId())).data;
|
||||
for (int m = 0; m < work.length; m++) {
|
||||
//m = row number, n = columns number
|
||||
System.arraycopy(work[m], 0, resultData[m], columnsDone, work[0].length);
|
||||
for (int n = 0; n < work[0].length; n++) {
|
||||
resultData[m][columnsDone + n] = work[m][n];
|
||||
}
|
||||
}
|
||||
columnsDone += work[0].length;
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ package com.iluwatar.masterworker.system.systemmaster;
|
||||
import com.iluwatar.masterworker.Input;
|
||||
import com.iluwatar.masterworker.Result;
|
||||
import com.iluwatar.masterworker.system.systemworkers.Worker;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The abstract Master class which contains private fields numOfWorkers (number of workers), workers
|
||||
@ -38,24 +38,24 @@ import java.util.List;
|
||||
|
||||
public abstract class Master {
|
||||
private final int numOfWorkers;
|
||||
private final List<Worker> workers;
|
||||
private final Hashtable<Integer, Result<?>> allResultData;
|
||||
private final ArrayList<Worker> workers;
|
||||
private int expectedNumResults;
|
||||
private Result<?> finalResult;
|
||||
private final Hashtable<Integer, Result> allResultData;
|
||||
private Result finalResult;
|
||||
|
||||
Master(int numOfWorkers) {
|
||||
this.numOfWorkers = numOfWorkers;
|
||||
this.workers = setWorkers(numOfWorkers);
|
||||
this.expectedNumResults = 0;
|
||||
this.allResultData = new Hashtable<>(numOfWorkers);
|
||||
this.allResultData = new Hashtable<Integer, Result>(numOfWorkers);
|
||||
this.finalResult = null;
|
||||
}
|
||||
|
||||
public Result<?> getFinalResult() {
|
||||
public Result getFinalResult() {
|
||||
return this.finalResult;
|
||||
}
|
||||
|
||||
Hashtable<Integer, Result<?>> getAllResultData() {
|
||||
Hashtable<Integer, Result> getAllResultData() {
|
||||
return this.allResultData;
|
||||
}
|
||||
|
||||
@ -63,41 +63,34 @@ public abstract class Master {
|
||||
return this.expectedNumResults;
|
||||
}
|
||||
|
||||
List<Worker> getWorkers() {
|
||||
ArrayList<Worker> getWorkers() {
|
||||
return this.workers;
|
||||
}
|
||||
|
||||
abstract List<Worker> setWorkers(int num);
|
||||
abstract ArrayList<Worker> setWorkers(int num);
|
||||
|
||||
public void doWork(Input<?> input) {
|
||||
public void doWork(Input input) {
|
||||
divideWork(input);
|
||||
}
|
||||
|
||||
private void divideWork(Input<?> input) {
|
||||
var dividedInput = input.divideData(numOfWorkers);
|
||||
private void divideWork(Input input) {
|
||||
ArrayList<Input> dividedInput = input.divideData(numOfWorkers);
|
||||
if (dividedInput != null) {
|
||||
this.expectedNumResults = dividedInput.size();
|
||||
for (var i = 0; i < this.expectedNumResults; i++) {
|
||||
for (int i = 0; i < this.expectedNumResults; i++) {
|
||||
//ith division given to ith worker in this.workers
|
||||
this.workers.get(i).setReceivedData(this, dividedInput.get(i));
|
||||
this.workers.get(i).start();
|
||||
}
|
||||
for (var i = 0; i < this.expectedNumResults; i++) {
|
||||
try {
|
||||
this.workers.get(i).join();
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("Error while executing thread");
|
||||
}
|
||||
this.workers.get(i).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveData(Result<?> data, Worker w) {
|
||||
public void receiveData(Result data, Worker w) {
|
||||
//check if can receive..if yes:
|
||||
collectResult(data, w.getWorkerId());
|
||||
}
|
||||
|
||||
private void collectResult(Result<?> data, int workerId) {
|
||||
private void collectResult(Result data, int workerId) {
|
||||
this.allResultData.put(workerId, data);
|
||||
if (this.allResultData.size() == this.expectedNumResults) {
|
||||
//all data received
|
||||
@ -105,5 +98,5 @@ public abstract class Master {
|
||||
}
|
||||
}
|
||||
|
||||
abstract Result<?> aggregateData();
|
||||
abstract Result aggregateData();
|
||||
}
|
||||
|
@ -41,12 +41,12 @@ public class ArrayTransposeWorker extends Worker {
|
||||
@Override
|
||||
ArrayResult executeOperation() {
|
||||
//number of rows in result matrix is equal to number of columns in input matrix and vice versa
|
||||
var arrayInput = (ArrayInput) this.getReceivedData();
|
||||
final var rows = arrayInput.data[0].length;
|
||||
final var cols = arrayInput.data.length;
|
||||
var resultData = new int[rows][cols];
|
||||
for (var i = 0; i < cols; i++) {
|
||||
for (var j = 0; j < rows; j++) {
|
||||
ArrayInput arrayInput = (ArrayInput) this.getReceivedData();
|
||||
final int rows = arrayInput.data[0].length;
|
||||
final int cols = arrayInput.data.length;
|
||||
int[][] resultData = new int[rows][cols];
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows; j++) {
|
||||
//flipping element positions along diagonal
|
||||
resultData[j][i] = arrayInput.data[i][j];
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ import com.iluwatar.masterworker.system.systemmaster.Master;
|
||||
public abstract class Worker extends Thread {
|
||||
private final Master master;
|
||||
private final int workerId;
|
||||
private Input<?> receivedData;
|
||||
private Input receivedData;
|
||||
|
||||
Worker(Master master, int id) {
|
||||
this.master = master;
|
||||
@ -47,23 +47,23 @@ public abstract class Worker extends Thread {
|
||||
return this.workerId;
|
||||
}
|
||||
|
||||
Input<?> getReceivedData() {
|
||||
Input getReceivedData() {
|
||||
return this.receivedData;
|
||||
}
|
||||
|
||||
public void setReceivedData(Master m, Input<?> i) {
|
||||
public void setReceivedData(Master m, Input i) {
|
||||
//check if ready to receive..if yes:
|
||||
this.receivedData = i;
|
||||
}
|
||||
|
||||
abstract Result<?> executeOperation();
|
||||
abstract Result executeOperation();
|
||||
|
||||
private void sendToMaster(Result<?> data) {
|
||||
private void sendToMaster(Result data) {
|
||||
this.master.receiveData(data, this);
|
||||
}
|
||||
|
||||
public void run() { //from Thread class
|
||||
var work = executeOperation();
|
||||
Result work = executeOperation();
|
||||
sendToMaster(work);
|
||||
}
|
||||
}
|
||||
|
@ -23,39 +23,38 @@
|
||||
|
||||
package com.iluwatar.masterworker;
|
||||
|
||||
import static com.iluwatar.masterworker.ArrayUtilityMethods.matricesSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Testing divideData method in {@link ArrayInput} class.
|
||||
*/
|
||||
* Testing divideData method in {@link ArrayInput} class.
|
||||
*/
|
||||
|
||||
class ArrayInputTest {
|
||||
|
||||
@Test
|
||||
void divideDataTest() {
|
||||
var rows = 10;
|
||||
var columns = 10;
|
||||
var inputMatrix = new int[rows][columns];
|
||||
var rand = new Random();
|
||||
for (var i = 0; i < rows; i++) {
|
||||
for (var j = 0; j < columns; j++) {
|
||||
int rows = 10;
|
||||
int columns = 10;
|
||||
int[][] inputMatrix = new int[rows][columns];
|
||||
Random rand = new Random();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
inputMatrix[i][j] = rand.nextInt(10);
|
||||
}
|
||||
}
|
||||
var i = new ArrayInput(inputMatrix);
|
||||
var table = i.divideData(4);
|
||||
var division1 = new int[][]{inputMatrix[0], inputMatrix[1], inputMatrix[2]};
|
||||
var division2 = new int[][]{inputMatrix[3], inputMatrix[4], inputMatrix[5]};
|
||||
var division3 = new int[][]{inputMatrix[6], inputMatrix[7]};
|
||||
var division4 = new int[][]{inputMatrix[8], inputMatrix[9]};
|
||||
assertTrue(matricesSame(table.get(0).data, division1)
|
||||
&& matricesSame(table.get(1).data, division2)
|
||||
&& matricesSame(table.get(2).data, division3)
|
||||
&& matricesSame(table.get(3).data, division4));
|
||||
ArrayInput i = new ArrayInput(inputMatrix);
|
||||
ArrayList<Input> table = i.divideData(4);
|
||||
int[][] division1 = new int[][] {inputMatrix[0], inputMatrix[1], inputMatrix[2]};
|
||||
int[][] division2 = new int[][] {inputMatrix[3], inputMatrix[4], inputMatrix[5]};
|
||||
int[][] division3 = new int[][] {inputMatrix[6], inputMatrix[7]};
|
||||
int[][] division4 = new int[][] {inputMatrix[8], inputMatrix[9]};
|
||||
assertTrue(ArrayUtilityMethods.matricesSame((int[][]) table.get(0).data, division1)
|
||||
&& ArrayUtilityMethods.matricesSame((int[][]) table.get(1).data, division2)
|
||||
&& ArrayUtilityMethods.matricesSame((int[][]) table.get(2).data, division3)
|
||||
&& ArrayUtilityMethods.matricesSame((int[][]) table.get(3).data, division4));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,27 +23,27 @@
|
||||
|
||||
package com.iluwatar.masterworker;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Testing utility methods in {@link ArrayUtilityMethods} class.
|
||||
*/
|
||||
* Testing utility methods in {@link ArrayUtilityMethods} class.
|
||||
*/
|
||||
|
||||
class ArrayUtilityMethodsTest {
|
||||
|
||||
@Test
|
||||
void arraysSameTest() {
|
||||
var arr1 = new int[]{1, 4, 2, 6};
|
||||
var arr2 = new int[]{1, 4, 2, 6};
|
||||
int[] arr1 = new int[] {1,4,2,6};
|
||||
int[] arr2 = new int[] {1,4,2,6};
|
||||
assertTrue(ArrayUtilityMethods.arraysSame(arr1, arr2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void matricesSameTest() {
|
||||
var matrix1 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
|
||||
var matrix2 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
|
||||
int[][] matrix1 = new int[][] {{1,4,2,6},{5,8,6,7}};
|
||||
int[][] matrix2 = new int[][] {{1,4,2,6},{5,8,6,7}};
|
||||
assertTrue(ArrayUtilityMethods.matricesSame(matrix1, matrix2));
|
||||
}
|
||||
|
||||
|
@ -23,38 +23,25 @@
|
||||
|
||||
package com.iluwatar.masterworker.system;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import com.iluwatar.masterworker.ArrayInput;
|
||||
import com.iluwatar.masterworker.ArrayResult;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Testing getResult method in {@link ArrayTransposeMasterWorker} class.
|
||||
*/
|
||||
* Testing getResult method in {@link ArrayTransposeMasterWorker} class.
|
||||
*/
|
||||
|
||||
class ArrayTransposeMasterWorkerTest {
|
||||
|
||||
@Test
|
||||
void getResultTest() {
|
||||
var atmw = new ArrayTransposeMasterWorker();
|
||||
var matrix = new int[][]{
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5}
|
||||
};
|
||||
var matrixTranspose = new int[][]{
|
||||
{1, 1, 1, 1, 1},
|
||||
{2, 2, 2, 2, 2},
|
||||
{3, 3, 3, 3, 3},
|
||||
{4, 4, 4, 4, 4},
|
||||
{5, 5, 5, 5, 5}
|
||||
};
|
||||
var i = new ArrayInput(matrix);
|
||||
var r = (ArrayResult) atmw.getResult(i);
|
||||
ArrayTransposeMasterWorker atmw = new ArrayTransposeMasterWorker();
|
||||
int[][] matrix = new int[][] {{1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}};
|
||||
int[][] matrixTranspose = new int[][] {{1,1,1,1,1}, {2,2,2,2,2}, {3,3,3,3,3}, {4,4,4,4,4}, {5,5,5,5,5}};
|
||||
ArrayInput i = new ArrayInput(matrix);
|
||||
ArrayResult r = (ArrayResult) atmw.getResult(i);
|
||||
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,29 +23,29 @@
|
||||
|
||||
package com.iluwatar.masterworker.system.systemworkers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.iluwatar.masterworker.ArrayInput;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import com.iluwatar.masterworker.system.systemmaster.ArrayTransposeMaster;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import com.iluwatar.masterworker.ArrayInput;
|
||||
import com.iluwatar.masterworker.ArrayResult;
|
||||
import com.iluwatar.masterworker.system.systemmaster.ArrayTransposeMaster;
|
||||
|
||||
/**
|
||||
* Testing executeOperation method in {@link ArrayTransposeWorker} class.
|
||||
*/
|
||||
* Testing executeOperation method in {@link ArrayTransposeWorker} class.
|
||||
*/
|
||||
|
||||
class ArrayTransposeWorkerTest {
|
||||
|
||||
@Test
|
||||
void executeOperationTest() {
|
||||
var atm = new ArrayTransposeMaster(1);
|
||||
var atw = new ArrayTransposeWorker(atm, 1);
|
||||
var matrix = new int[][]{{2, 4}, {3, 5}};
|
||||
var matrixTranspose = new int[][]{{2, 3}, {4, 5}};
|
||||
var i = new ArrayInput(matrix);
|
||||
ArrayTransposeMaster atm = new ArrayTransposeMaster(1);
|
||||
ArrayTransposeWorker atw = new ArrayTransposeWorker(atm, 1);
|
||||
int[][] matrix = new int[][] {{2,4}, {3,5}};
|
||||
int[][] matrixTranspose = new int[][] {{2,3}, {4,5}};
|
||||
ArrayInput i = new ArrayInput(matrix);
|
||||
atw.setReceivedData(atm, i);
|
||||
var r = atw.executeOperation();
|
||||
ArrayResult r = atw.executeOperation();
|
||||
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package com.iluwatar.mediator;
|
||||
* Action enumeration.
|
||||
*/
|
||||
public enum Action {
|
||||
|
||||
HUNT("hunted a rabbit", "arrives for dinner"),
|
||||
TALE("tells a tale", "comes to listen"),
|
||||
GOLD("found gold", "takes his share of the gold"),
|
||||
|
@ -55,10 +55,10 @@ public class App {
|
||||
|
||||
// create party and members
|
||||
Party party = new PartyImpl();
|
||||
var hobbit = new Hobbit();
|
||||
var wizard = new Wizard();
|
||||
var rogue = new Rogue();
|
||||
var hunter = new Hunter();
|
||||
Hobbit hobbit = new Hobbit();
|
||||
Wizard wizard = new Wizard();
|
||||
Rogue rogue = new Rogue();
|
||||
Hunter hunter = new Hunter();
|
||||
|
||||
// add party members
|
||||
party.addMember(hobbit);
|
||||
|
@ -39,7 +39,7 @@ public class PartyImpl implements Party {
|
||||
|
||||
@Override
|
||||
public void act(PartyMember actor, Action action) {
|
||||
for (var member : members) {
|
||||
for (PartyMember member : members) {
|
||||
if (!member.equals(actor)) {
|
||||
member.partyAction(action);
|
||||
}
|
||||
|
@ -26,12 +26,15 @@ package com.iluwatar.mediator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
App.main(new String[]{});
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
||||
|
@ -43,10 +43,10 @@ public class PartyImplTest {
|
||||
*/
|
||||
@Test
|
||||
public void testPartyAction() {
|
||||
final var partyMember1 = mock(PartyMember.class);
|
||||
final var partyMember2 = mock(PartyMember.class);
|
||||
final PartyMember partyMember1 = mock(PartyMember.class);
|
||||
final PartyMember partyMember2 = mock(PartyMember.class);
|
||||
|
||||
final var party = new PartyImpl();
|
||||
final PartyImpl party = new PartyImpl();
|
||||
party.addMember(partyMember1);
|
||||
party.addMember(partyMember2);
|
||||
|
||||
@ -58,6 +58,7 @@ public class PartyImplTest {
|
||||
verify(partyMember2).partyAction(Action.GOLD);
|
||||
|
||||
verifyNoMoreInteractions(partyMember1, partyMember2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,24 +23,24 @@
|
||||
|
||||
package com.iluwatar.mediator;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Date: 12/19/15 - 10:13 PM
|
||||
*
|
||||
@ -48,12 +48,12 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class PartyMemberTest {
|
||||
|
||||
static Stream<Arguments> dataProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of((Supplier<PartyMember>) Hobbit::new),
|
||||
Arguments.of((Supplier<PartyMember>) Hunter::new),
|
||||
Arguments.of((Supplier<PartyMember>) Rogue::new),
|
||||
Arguments.of((Supplier<PartyMember>) Wizard::new)
|
||||
static Collection<Supplier<PartyMember>[]> dataProvider() {
|
||||
return List.of(
|
||||
new Supplier[]{Hobbit::new},
|
||||
new Supplier[]{Hunter::new},
|
||||
new Supplier[]{Rogue::new},
|
||||
new Supplier[]{Wizard::new}
|
||||
);
|
||||
}
|
||||
|
||||
@ -75,9 +75,9 @@ public class PartyMemberTest {
|
||||
@ParameterizedTest
|
||||
@MethodSource("dataProvider")
|
||||
public void testPartyAction(Supplier<PartyMember> memberSupplier) {
|
||||
final var member = memberSupplier.get();
|
||||
final PartyMember member = memberSupplier.get();
|
||||
|
||||
for (final var action : Action.values()) {
|
||||
for (final Action action : Action.values()) {
|
||||
member.partyAction(action);
|
||||
assertEquals(member.toString() + " " + action.getDescription(), appender.getLastMessage());
|
||||
}
|
||||
@ -91,16 +91,16 @@ public class PartyMemberTest {
|
||||
@ParameterizedTest
|
||||
@MethodSource("dataProvider")
|
||||
public void testAct(Supplier<PartyMember> memberSupplier) {
|
||||
final var member = memberSupplier.get();
|
||||
final PartyMember member = memberSupplier.get();
|
||||
|
||||
member.act(Action.GOLD);
|
||||
assertEquals(0, appender.getLogSize());
|
||||
|
||||
final var party = mock(Party.class);
|
||||
final Party party = mock(Party.class);
|
||||
member.joinedParty(party);
|
||||
assertEquals(member.toString() + " joins the party", appender.getLastMessage());
|
||||
|
||||
for (final var action : Action.values()) {
|
||||
for (final Action action : Action.values()) {
|
||||
member.act(action);
|
||||
assertEquals(member.toString() + " " + action.toString(), appender.getLastMessage());
|
||||
verify(party).act(member, action);
|
||||
@ -114,16 +114,16 @@ public class PartyMemberTest {
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("dataProvider")
|
||||
public void testToString(Supplier<PartyMember> memberSupplier) {
|
||||
final var member = memberSupplier.get();
|
||||
final var memberClass = member.getClass();
|
||||
public void testToString(Supplier<PartyMember> memberSupplier) throws Exception {
|
||||
final PartyMember member = memberSupplier.get();
|
||||
final Class<? extends PartyMember> memberClass = member.getClass();
|
||||
assertEquals(memberClass.getSimpleName(), member.toString());
|
||||
}
|
||||
|
||||
private static class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
||||
|
||||
public InMemoryAppender(Class<?> clazz) {
|
||||
public InMemoryAppender(Class clazz) {
|
||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||
start();
|
||||
}
|
||||
|
@ -34,12 +34,9 @@ Let's first define the types of stars we are capable to handle.
|
||||
|
||||
```java
|
||||
public enum StarType {
|
||||
SUN("sun"),
|
||||
RED_GIANT("red giant"),
|
||||
WHITE_DWARF("white dwarf"),
|
||||
SUPERNOVA("supernova"),
|
||||
DEAD("dead star"),
|
||||
UNDEFINED("");
|
||||
|
||||
SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
|
||||
"dead star"), UNDEFINED("");
|
||||
|
||||
private final String title;
|
||||
|
||||
@ -98,7 +95,8 @@ public class Star {
|
||||
}
|
||||
|
||||
StarMemento getMemento() {
|
||||
var state = new StarMementoInternal();
|
||||
|
||||
StarMementoInternal state = new StarMementoInternal();
|
||||
state.setAgeYears(ageYears);
|
||||
state.setMassTons(massTons);
|
||||
state.setType(type);
|
||||
@ -106,7 +104,8 @@ public class Star {
|
||||
}
|
||||
|
||||
void setMemento(StarMemento memento) {
|
||||
var state = (StarMementoInternal) memento;
|
||||
|
||||
StarMementoInternal state = (StarMementoInternal) memento;
|
||||
this.type = state.getType();
|
||||
this.ageYears = state.getAgeYears();
|
||||
this.massTons = state.getMassTons();
|
||||
@ -153,8 +152,8 @@ public class Star {
|
||||
And finally here's how we use the mementos to store and restore star states.
|
||||
|
||||
```java
|
||||
var states = new Stack<>();
|
||||
var star = new Star(StarType.SUN, 10000000, 500000);
|
||||
Stack<StarMemento> states = new Stack<>();
|
||||
Star star = new Star(StarType.SUN, 10000000, 500000);
|
||||
LOGGER.info(star.toString());
|
||||
states.add(star.getMemento());
|
||||
star.timePasses();
|
||||
|
@ -52,9 +52,9 @@ public class App {
|
||||
* Program entry point.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
var states = new Stack<StarMemento>();
|
||||
Stack<StarMemento> states = new Stack<>();
|
||||
|
||||
var star = new Star(StarType.SUN, 10000000, 500000);
|
||||
Star star = new Star(StarType.SUN, 10000000, 500000);
|
||||
LOGGER.info(star.toString());
|
||||
states.add(star.getMemento());
|
||||
star.timePasses();
|
||||
|
@ -70,18 +70,22 @@ public class Star {
|
||||
}
|
||||
|
||||
StarMemento getMemento() {
|
||||
var state = new StarMementoInternal();
|
||||
|
||||
StarMementoInternal state = new StarMementoInternal();
|
||||
state.setAgeYears(ageYears);
|
||||
state.setMassTons(massTons);
|
||||
state.setType(type);
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
void setMemento(StarMemento memento) {
|
||||
var state = (StarMementoInternal) memento;
|
||||
|
||||
StarMementoInternal state = (StarMementoInternal) memento;
|
||||
this.type = state.getType();
|
||||
this.ageYears = state.getAgeYears();
|
||||
this.massTons = state.getMassTons();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,12 +27,9 @@ package com.iluwatar.memento;
|
||||
* StarType enumeration.
|
||||
*/
|
||||
public enum StarType {
|
||||
SUN("sun"),
|
||||
RED_GIANT("red giant"),
|
||||
WHITE_DWARF("white dwarf"),
|
||||
SUPERNOVA("supernova"),
|
||||
DEAD("dead star"),
|
||||
UNDEFINED("");
|
||||
|
||||
SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
|
||||
"dead star"), UNDEFINED("");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@ -26,12 +26,15 @@ package com.iluwatar.memento;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
App.main(new String[]{});
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,10 @@
|
||||
|
||||
package com.iluwatar.memento;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Date: 12/20/15 - 10:08 AM
|
||||
*
|
||||
@ -39,7 +39,7 @@ public class StarTest {
|
||||
*/
|
||||
@Test
|
||||
public void testTimePasses() {
|
||||
final var star = new Star(StarType.SUN, 1, 2);
|
||||
final Star star = new Star(StarType.SUN, 1, 2);
|
||||
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
@ -66,16 +66,16 @@ public class StarTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetMemento() {
|
||||
final var star = new Star(StarType.SUN, 1, 2);
|
||||
final var firstMemento = star.getMemento();
|
||||
final Star star = new Star(StarType.SUN, 1, 2);
|
||||
final StarMemento firstMemento = star.getMemento();
|
||||
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
final var secondMemento = star.getMemento();
|
||||
final StarMemento secondMemento = star.getMemento();
|
||||
assertEquals("red giant age: 2 years mass: 16 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
final var thirdMemento = star.getMemento();
|
||||
final StarMemento thirdMemento = star.getMemento();
|
||||
assertEquals("white dwarf age: 4 years mass: 128 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
|
@ -47,9 +47,9 @@ public class App {
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// create model, view and controller
|
||||
var giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
var view = new GiantView();
|
||||
var controller = new GiantController(giant, view);
|
||||
GiantModel giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
GiantView view = new GiantView();
|
||||
GiantController controller = new GiantController(giant, view);
|
||||
// initial display
|
||||
controller.updateView();
|
||||
// controller receives some interactions that affect the giant
|
||||
|
@ -27,9 +27,8 @@ package com.iluwatar.model.view.controller;
|
||||
* Fatigue enumeration.
|
||||
*/
|
||||
public enum Fatigue {
|
||||
ALERT("alert"),
|
||||
TIRED("tired"),
|
||||
SLEEPING("sleeping");
|
||||
|
||||
ALERT("alert"), TIRED("tired"), SLEEPING("sleeping");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@ -36,7 +36,6 @@ public class GiantController {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Health getHealth() {
|
||||
return giant.getHealth();
|
||||
}
|
||||
@ -45,7 +44,6 @@ public class GiantController {
|
||||
this.giant.setHealth(health);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Fatigue getFatigue() {
|
||||
return giant.getFatigue();
|
||||
}
|
||||
@ -54,7 +52,6 @@ public class GiantController {
|
||||
this.giant.setFatigue(fatigue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Nourishment getNourishment() {
|
||||
return giant.getNourishment();
|
||||
}
|
||||
|
@ -27,9 +27,8 @@ package com.iluwatar.model.view.controller;
|
||||
* Health enumeration.
|
||||
*/
|
||||
public enum Health {
|
||||
HEALTHY("healthy"),
|
||||
WOUNDED("wounded"),
|
||||
DEAD("dead");
|
||||
|
||||
HEALTHY("healthy"), WOUNDED("wounded"), DEAD("dead");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@ -27,9 +27,8 @@ package com.iluwatar.model.view.controller;
|
||||
* Nourishment enumeration.
|
||||
*/
|
||||
public enum Nourishment {
|
||||
SATURATED("saturated"),
|
||||
HUNGRY("hungry"),
|
||||
STARVING("starving");
|
||||
|
||||
SATURATED("saturated"), HUNGRY("hungry"), STARVING("starving");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@ -26,12 +26,15 @@ package com.iluwatar.model.view.controller;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
App.main(new String[]{});
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,13 @@
|
||||
|
||||
package com.iluwatar.model.view.controller;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Date: 12/20/15 - 2:19 PM
|
||||
*
|
||||
@ -42,20 +42,19 @@ public class GiantControllerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetHealth() {
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
for (final var health : Health.values()) {
|
||||
for (final Health health : Health.values()) {
|
||||
controller.setHealth(health);
|
||||
verify(model).setHealth(health);
|
||||
verifyZeroInteractions(view);
|
||||
}
|
||||
|
||||
controller.getHealth();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
verify(model).getHealth();
|
||||
|
||||
verifyNoMoreInteractions(model, view);
|
||||
@ -66,20 +65,19 @@ public class GiantControllerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetFatigue() {
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
for (final var fatigue : Fatigue.values()) {
|
||||
for (final Fatigue fatigue : Fatigue.values()) {
|
||||
controller.setFatigue(fatigue);
|
||||
verify(model).setFatigue(fatigue);
|
||||
verifyZeroInteractions(view);
|
||||
}
|
||||
|
||||
controller.getFatigue();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
verify(model).getFatigue();
|
||||
|
||||
verifyNoMoreInteractions(model, view);
|
||||
@ -90,20 +88,19 @@ public class GiantControllerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetNourishment() {
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
for (final var nourishment : Nourishment.values()) {
|
||||
for (final Nourishment nourishment : Nourishment.values()) {
|
||||
controller.setNourishment(nourishment);
|
||||
verify(model).setNourishment(nourishment);
|
||||
verifyZeroInteractions(view);
|
||||
}
|
||||
|
||||
controller.getNourishment();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
verify(model).getNourishment();
|
||||
|
||||
verifyNoMoreInteractions(model, view);
|
||||
@ -111,9 +108,9 @@ public class GiantControllerTest {
|
||||
|
||||
@Test
|
||||
public void testUpdateView() {
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
|
@ -23,10 +23,10 @@
|
||||
|
||||
package com.iluwatar.model.view.controller;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Date: 12/20/15 - 2:10 PM
|
||||
*
|
||||
@ -39,13 +39,12 @@ public class GiantModelTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetHealth() {
|
||||
final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
assertEquals(Health.HEALTHY, model.getHealth());
|
||||
var messageFormat = "The giant looks %s, alert and saturated.";
|
||||
for (final var health : Health.values()) {
|
||||
for (final Health health : Health.values()) {
|
||||
model.setHealth(health);
|
||||
assertEquals(health, model.getHealth());
|
||||
assertEquals(String.format(messageFormat, health), model.toString());
|
||||
assertEquals("The giant looks " + health.toString() + ", alert and saturated.", model.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,13 +53,12 @@ public class GiantModelTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetFatigue() {
|
||||
final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
assertEquals(Fatigue.ALERT, model.getFatigue());
|
||||
var messageFormat = "The giant looks healthy, %s and saturated.";
|
||||
for (final var fatigue : Fatigue.values()) {
|
||||
for (final Fatigue fatigue : Fatigue.values()) {
|
||||
model.setFatigue(fatigue);
|
||||
assertEquals(fatigue, model.getFatigue());
|
||||
assertEquals(String.format(messageFormat, fatigue), model.toString());
|
||||
assertEquals("The giant looks healthy, " + fatigue.toString() + " and saturated.", model.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,13 +67,12 @@ public class GiantModelTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetNourishment() {
|
||||
final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
assertEquals(Nourishment.SATURATED, model.getNourishment());
|
||||
var messageFormat = "The giant looks healthy, alert and %s.";
|
||||
for (final var nourishment : Nourishment.values()) {
|
||||
for (final Nourishment nourishment : Nourishment.values()) {
|
||||
model.setNourishment(nourishment);
|
||||
assertEquals(nourishment, model.getNourishment());
|
||||
assertEquals(String.format(messageFormat, nourishment), model.toString());
|
||||
assertEquals("The giant looks healthy, alert and " + nourishment.toString() + ".", model.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -61,9 +62,9 @@ public class GiantViewTest {
|
||||
*/
|
||||
@Test
|
||||
public void testDisplayGiant() {
|
||||
final var view = new GiantView();
|
||||
final GiantView view = new GiantView();
|
||||
|
||||
final var model = mock(GiantModel.class);
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
view.displayGiant(model);
|
||||
|
||||
assertEquals(model.toString(), appender.getLastMessage());
|
||||
@ -73,10 +74,10 @@ public class GiantViewTest {
|
||||
/**
|
||||
* Logging Appender Implementation
|
||||
*/
|
||||
public static class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
public class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
||||
|
||||
public InMemoryAppender(Class<?> clazz) {
|
||||
public InMemoryAppender(Class clazz) {
|
||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||
start();
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
var loader = new FileLoader();
|
||||
var frame = new FileSelectorJFrame();
|
||||
var presenter = new FileSelectorPresenter(frame);
|
||||
FileLoader loader = new FileLoader();
|
||||
FileSelectorJFrame frame = new FileSelectorJFrame();
|
||||
FileSelectorPresenter presenter = new FileSelectorPresenter(frame);
|
||||
presenter.setLoader(loader);
|
||||
presenter.start();
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.Serializable;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -60,11 +59,18 @@ public class FileLoader implements Serializable {
|
||||
* Loads the data of the file specified.
|
||||
*/
|
||||
public String loadData() {
|
||||
var dataFileName = this.fileName;
|
||||
try (var br = new BufferedReader(new FileReader(new File(dataFileName)))) {
|
||||
var result = br.lines().collect(Collectors.joining("\n"));
|
||||
String dataFileName = this.fileName;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(new File(dataFileName)))) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line).append('\n');
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
return result;
|
||||
|
||||
return sb.toString();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("File {} does not exist", dataFileName);
|
||||
}
|
||||
|
@ -55,6 +55,16 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
*/
|
||||
private final JButton cancel;
|
||||
|
||||
/**
|
||||
* The information label.
|
||||
*/
|
||||
private final JLabel info;
|
||||
|
||||
/**
|
||||
* The contents label.
|
||||
*/
|
||||
private final JLabel contents;
|
||||
|
||||
/**
|
||||
* The text field for giving the name of the file that we want to open.
|
||||
*/
|
||||
@ -65,6 +75,11 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
*/
|
||||
private final JTextArea area;
|
||||
|
||||
/**
|
||||
* The panel that will hold our widgets.
|
||||
*/
|
||||
private final JPanel panel;
|
||||
|
||||
/**
|
||||
* The Presenter component that the frame will interact with.
|
||||
*/
|
||||
@ -87,7 +102,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
/*
|
||||
* Add the panel.
|
||||
*/
|
||||
var panel = new JPanel();
|
||||
this.panel = new JPanel();
|
||||
panel.setLayout(null);
|
||||
this.add(panel);
|
||||
panel.setBounds(0, 0, 500, 200);
|
||||
@ -96,32 +111,32 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
/*
|
||||
* Add the info label.
|
||||
*/
|
||||
var info = new JLabel("File Name :");
|
||||
panel.add(info);
|
||||
this.info = new JLabel("File Name :");
|
||||
this.panel.add(info);
|
||||
info.setBounds(30, 10, 100, 30);
|
||||
|
||||
/*
|
||||
* Add the contents label.
|
||||
*/
|
||||
var contents = new JLabel("File contents :");
|
||||
panel.add(contents);
|
||||
contents.setBounds(30, 100, 120, 30);
|
||||
this.contents = new JLabel("File contents :");
|
||||
this.panel.add(contents);
|
||||
this.contents.setBounds(30, 100, 120, 30);
|
||||
|
||||
/*
|
||||
* Add the text field.
|
||||
*/
|
||||
this.input = new JTextField(100);
|
||||
panel.add(input);
|
||||
this.panel.add(input);
|
||||
this.input.setBounds(150, 15, 200, 20);
|
||||
|
||||
/*
|
||||
* Add the text area.
|
||||
*/
|
||||
this.area = new JTextArea(100, 100);
|
||||
var pane = new JScrollPane(area);
|
||||
JScrollPane pane = new JScrollPane(area);
|
||||
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
panel.add(pane);
|
||||
this.panel.add(pane);
|
||||
this.area.setEditable(false);
|
||||
pane.setBounds(150, 100, 250, 80);
|
||||
|
||||
@ -129,7 +144,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
* Add the OK button.
|
||||
*/
|
||||
this.ok = new JButton("OK");
|
||||
panel.add(ok);
|
||||
this.panel.add(ok);
|
||||
this.ok.setBounds(250, 50, 100, 25);
|
||||
this.ok.addActionListener(this);
|
||||
|
||||
@ -137,7 +152,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
* Add the cancel button.
|
||||
*/
|
||||
this.cancel = new JButton("Cancel");
|
||||
panel.add(this.cancel);
|
||||
this.panel.add(this.cancel);
|
||||
this.cancel.setBounds(380, 50, 100, 25);
|
||||
this.cancel.addActionListener(this);
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class FileSelectorPresenter implements Serializable {
|
||||
}
|
||||
|
||||
if (loader.fileExists()) {
|
||||
var data = loader.loadData();
|
||||
String data = loader.loadData();
|
||||
view.displayData(data);
|
||||
} else {
|
||||
view.showMessage("The file specified does not exist.");
|
||||
|
@ -26,13 +26,16 @@ package com.iluwatar.model.view.presenter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
App.main(new String[]{});
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user