├── .gitignore
├── Chapter01
├── README.md
├── apie
│ ├── AbstractVehicle.java
│ ├── Bus.java
│ ├── Car.java
│ ├── CommonCar.java
│ ├── Example1_2Main.java
│ ├── SportCar.java
│ ├── Truck.java
│ ├── Vehicle.java
│ └── VehicleInterface.java
└── solid
│ ├── dip
│ └── Garage.java
│ ├── general
│ ├── Car.java
│ ├── CarWash.java
│ ├── Example1_6Main.java
│ ├── Example1_7Main.java
│ ├── SportCar.java
│ ├── Truck.java
│ └── Vehicle.java
│ ├── spi_malicious
│ ├── Bike.java
│ ├── Car.java
│ ├── Example1_8Main.java
│ └── Vehicle.java
│ ├── spi_optimal
│ ├── Bike.java
│ ├── Car.java
│ ├── Example1_9Main.java
│ ├── HasEngine.java
│ ├── HasPedals.java
│ └── Vehicle.java
│ └── srp
│ ├── Engine.java
│ ├── Vehicle.java
│ └── VehicleComputer.java
├── Chapter02
├── Figure_2_4_Program_Reading.jfr
├── Jep323.java
├── Jep361.java
├── Jep394.java
├── Jep395.java
├── Jep420.java
├── MultiThreadedProgram.java
├── Program.java
├── README.md
├── StreamMain.java
├── jep409
│ ├── Bus.java
│ ├── Car.java
│ ├── Jep409Main.java
│ ├── Motorbike.java
│ ├── NormalEngine.java
│ ├── SlowEngine.java
│ ├── SuperCar.java
│ └── Vehicle.java
├── module-example.jar
└── module-example
│ ├── example
│ └── ExampleMain.java
│ └── module-info.java
├── Chapter03
├── README.md
├── abstract_factory
│ ├── AbstractFactory.java
│ ├── AbstractFactoryMain.java
│ ├── CarFactory.java
│ ├── FactoryProvider.java
│ ├── FastCar.java
│ ├── HeavyTruck.java
│ ├── LightTruck.java
│ ├── SlowCar.java
│ ├── TruckFactory.java
│ └── Vehicle.java
├── builder
│ ├── BuilderMain.java
│ ├── FastVehicle.java
│ ├── Part.java
│ ├── RecordPart.java
│ ├── SlowVehicle.java
│ ├── StandardPart.java
│ ├── SuperVehicle.java
│ ├── Vehicle.java
│ └── VehicleBuilder.java
├── dependency_injection
│ ├── DependencyInjectionMain.java
│ ├── DependencyInjectionServiceLoaderMain.java
│ ├── Engine.java
│ ├── EngineServiceLoader.java
│ ├── EngineServiceProvider.java
│ ├── FastEngine.java
│ ├── META-INF
│ │ └── services
│ │ │ └── Engine
│ ├── SportVehicle.java
│ └── Vehicle.java
├── factory_method
│ ├── FactoryMethodMain.java
│ ├── SportCar.java
│ ├── SuvCar.java
│ ├── Vehicle.java
│ └── VehicleFactory.java
├── lazy_initialization
│ ├── LazyInitializationMain.java
│ ├── LazyVehicle.java
│ ├── Vehicle.java
│ └── VehicleProvider.java
├── object_pool
│ ├── AbstractGaragePool.java
│ ├── ObjectPoolMain.java
│ ├── PooledVehicle.java
│ ├── PooledVehicleGarage.java
│ └── Vehicle.java
├── prototype
│ ├── FastCar.java
│ ├── PrototypeMain.java
│ ├── SlowCar.java
│ ├── Vehicle.java
│ └── VehicleCache.java
└── singleton
│ ├── Engine.java
│ ├── OnlyEngine.java
│ ├── OnlyEngineEnum.java
│ ├── OnlyVehicle.java
│ └── SingletonMain.java
├── Chapter04
├── README.md
├── adapter
│ ├── AdapterMain.java
│ ├── ElectricEngine.java
│ ├── Engine.java
│ ├── PetrolEngine.java
│ └── Vehicle.java
├── bridge
│ ├── BridgeMain.java
│ ├── DieselEngine.java
│ ├── Engine.java
│ ├── PetrolEngine.java
│ ├── PickupVehicle.java
│ ├── SportVehicle.java
│ └── Vehicle.java
├── composite
│ ├── CompositeMain.java
│ ├── SportVehicle.java
│ ├── Vehicle.java
│ ├── VehicleElement.java
│ └── VehiclePart.java
├── decorator
│ ├── DecoratorMain.java
│ ├── SportVehicle.java
│ ├── StandardVehicle.java
│ ├── TunedVehicleDecorator.java
│ └── Vehicle.java
├── facade
│ ├── DieselVehicle.java
│ ├── FacadeMain.java
│ ├── PetrolVehicle.java
│ └── Vehicle.java
├── filter
│ ├── FilterMain.java
│ ├── Rule.java
│ ├── RuleAnalog.java
│ ├── RuleAnd.java
│ ├── RuleOr.java
│ ├── RuleType.java
│ └── Sensor.java
├── flyweight
│ ├── FlyweightMain.java
│ ├── Vehicle.java
│ ├── VehicleGarage.java
│ └── VehicleType.java
├── front_controller
│ ├── BreaksUnit.java
│ ├── EngineUnit.java
│ ├── FrontControllerMain.java
│ ├── RequestDispatcher.java
│ └── VehicleController.java
├── marker
│ ├── BreaksSensor.java
│ ├── CertifiedAnnotation.java
│ ├── CertifiedSensor.java
│ ├── ConsumptionSensor.java
│ ├── EngineSensor.java
│ ├── MarkerMain.java
│ └── Sensor.java
├── module
│ ├── BreaksModule.java
│ ├── EngineModule.java
│ ├── ModuleMain.java
│ └── VehicleModule.java
├── proxy
│ ├── ProxyMain.java
│ ├── Vehicle.java
│ ├── VehicleProxy.java
│ └── VehicleReal.java
└── twin
│ ├── AbstractVehiclePart.java
│ ├── TwinMain.java
│ ├── VehicleBreaks.java
│ └── VehicleEngine.java
├── Chapter05
├── README.md
├── caching
│ ├── BreakSystem.java
│ ├── CachingMain.java
│ ├── EngineSystem.java
│ ├── SuspensionSystem.java
│ ├── SystemCache.java
│ ├── Vehicle.java
│ └── VehicleSystem.java
├── chain_responsibility
│ ├── ChainOfResponsibilityMain.java
│ ├── DriverSystem.java
│ ├── EngineSystem.java
│ ├── SystemType.java
│ ├── TransmissionSystem.java
│ └── VehicleSystem.java
├── command
│ ├── CommandMain.java
│ ├── Driver.java
│ ├── StartCommand.java
│ ├── StopCommand.java
│ ├── Vehicle.java
│ └── VehicleCommand.java
├── interpreter
│ ├── Expression.java
│ ├── IntegerExpression.java
│ ├── InterpreterMain.java
│ ├── MinusExpression.java
│ └── PlusExpression.java
├── iterator
│ ├── IteratorMain.java
│ ├── PartsIterator.java
│ ├── StandardVehicle.java
│ ├── Vehicle.java
│ └── VehiclePart.java
├── mediator
│ ├── MediatorMain.java
│ ├── Sensor.java
│ └── VehicleProcessor.java
├── memento
│ ├── AirConditionSystemCareTaker.java
│ ├── AirConditionSystemOriginator.java
│ ├── MementoMain.java
│ └── SystemMemento.java
├── null_object
│ ├── AbstractSensor.java
│ ├── NullObjectMain.java
│ ├── NullSensor.java
│ ├── VehicleSensor.java
│ └── VehicleSensorsProvider.java
├── observer
│ ├── CockpitObserver.java
│ ├── EngineObserver.java
│ ├── ObserverMain.java
│ ├── SystemObserver.java
│ └── VehicleSystem.java
├── pipeline
│ ├── BreakProcessor.java
│ ├── Element.java
│ ├── EngineProcessor.java
│ ├── PipeElement.java
│ ├── PipelineMain.java
│ ├── Processor.java
│ ├── SystemElement.java
│ └── TransmissionProcessor.java
├── state
│ ├── InitState.java
│ ├── StartState.java
│ ├── StateMain.java
│ ├── StopState.java
│ ├── Vehicle.java
│ └── VehicleState.java
├── strategy
│ ├── BusStrategy.java
│ ├── CarStrategy.java
│ ├── StrategyMain.java
│ ├── TransportStrategy.java
│ ├── TruckStrategy.java
│ └── VehicleDriver.java
├── template_method
│ ├── BreaksSensor.java
│ ├── EngineSensor.java
│ ├── TemplateMethodMain.java
│ └── VehicleSensor.java
└── visitor
│ ├── BreaksCheck.java
│ ├── CheckVisitor.java
│ ├── EngineCheck.java
│ ├── SuspensionCheck.java
│ ├── SystemCheck.java
│ ├── VehicleCheck.java
│ ├── VehicleSystemCheckVisitor.java
│ └── VisitorMain.java
├── Chapter06
├── README.md
├── active_object
│ ├── ActiveObjectMain.java
│ ├── ActiveObjectUtil.java
│ ├── MovingVehicle.java
│ └── SportVehicle.java
├── active_object_figure_6_1.jfr
├── async_method
│ ├── AsyncMethodMain.java
│ ├── AsyncMethodUtils.java
│ ├── SensorCallback.java
│ ├── SensorExecutor.java
│ ├── SensorResult.java
│ ├── TempSensorCallback.java
│ ├── TempSensorExecutor.java
│ ├── TempSensorResult.java
│ └── TempSensorTask.java
├── async_method_figure_6_3.jfr
├── balking
│ ├── BalkingMain.java
│ ├── Vehicle.java
│ └── VehicleState.java
├── balking_figure_6_5.jfr
├── double_checked
│ ├── DoubleCheckedLockingMain.java
│ ├── Vehicle.java
│ ├── VehicleSingleton.java
│ └── VehicleSingletonChecked.java
├── double_checked_figure_6_7.jfr
├── prod_con
│ ├── Event.java
│ ├── EventConsumer.java
│ ├── EventProducer.java
│ ├── EventsContainer.java
│ ├── ProdConThreadFactory.java
│ ├── ProducerConsumerMain.java
│ └── ProducerConsumerUtil.java
├── prod_con_figure_6_11.jfr
├── read_write_lock
│ ├── ReadWriteLockMain.java
│ ├── ReadWriteLockUtils.java
│ ├── Sensor.java
│ ├── SensorReader.java
│ ├── SensorWriter.java
│ └── read_write_lock_figure_6_9.jfr
├── scheduler
│ ├── CustomScheduledThreadPoolExecutor.java
│ ├── CustomScheduledThreadPoolMain.java
│ ├── CustomScheduler.java
│ ├── CustomSchedulerMain.java
│ └── SensorTask.java
├── scheduler_custom_figure_6_13.jfr
├── scheduler_pool_figure_6_15.jfr
├── thread_pool
│ ├── SensorTask.java
│ ├── SensorWorker.java
│ ├── TemperatureTask.java
│ └── ThreadPoolMain.java
└── thread_pool_figure_6_17.jfr
├── Chapter07
├── README.md
├── anti_patterns
│ ├── VehicleBlob.java
│ ├── VehicleCO.java
│ ├── VehicleCOImpl.java
│ └── VehicleSpaghetti.java
├── busy_method
│ ├── BusyMethodMain.java
│ ├── ThreadContainer.java
│ ├── VehicleAnalyticalWorker.java
│ ├── VehicleAnalyticalWorkerEvent.java
│ └── VehicleDataContainer.java
├── busy_method_vehicle_data_analyzer_figure_7_3_corrupted.jfr
├── busy_method_vehicle_data_analyzer_figure_7_4_corrected.jfr
├── garbage
│ ├── GarbageMain.java
│ ├── Sensor.java
│ ├── SensorAlarmSystemUtil.java
│ ├── SensorAlarmWorker.java
│ ├── SensorAlarmWorkerEvent.java
│ └── ThreadContainer.java
├── garbage_sensor_alarm_figure_7_1_corrupted.jfr
└── garbage_sensor_alarm_figure_7_2_corected.jfr
├── HowToCompileAndExecute.md
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vcode
2 | out
--------------------------------------------------------------------------------
/Chapter01/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
2 | ## Chapter 1 - getting into software design patterns examples
3 | 1. **OOP** pilars **APIE** :
4 | - encapuslation (E) :
5 | - [Example 1.1 - `Vehicle.java`](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/Vehicle.java)
6 | - inheritance (I)
7 | - [`Car.java` implementation extends `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/Car.java)
8 | - [`SportCar.java` class extends `AbstractVehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/SportCar.java)
9 | - polymorphism (P)
10 | - method overloading
11 | - [Figure 1.5 - `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/Vehicle.java)
12 | - method overriding
13 | - [Example 1.2, Figure 1.6 - `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/Vehicle.java)
14 | - [Example 1.2, Figure 1.6 - `Car` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/Car.java)
15 | - abstraciton (A)
16 | - abstract `class`
17 | - [Example 1.3, Figure 1.7 - `AbstractVehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/AbstractVehicle.java)
18 | - [Example 1.3, Figure 1.7 - `CommonCar` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/CommonCar.java)
19 | - [Example 1.3, Figure 1.7 - `SportCar` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/SportCar.java)
20 | - interface `class`
21 | - [Example 1.4, Figure 1.8 - `VehicleInterface` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/VehicleInterface.java)
22 | - [Example 1.4, Figure 1.8 - `Truck` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/Truck.java)
23 | - [Example 1.4, Figure 1.8 - `Bus` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/Bus.java)
24 | - abstract and interface `classes`
25 | - [Figure 1.9 - `VehicleInterface` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/VehicleInterface.java)
26 | - [Figure 1.9 - `AbstractVehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/AbstractVehicle.java)
27 | - [Figure 1.9 - `Truck` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/CommonCar.java)
28 | - [Figure 1.9 - `Bus` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/apie/SportCar.java)
29 |
30 |
31 | 2. SOLID Principles
32 | - single-responsiblity principle (SRP)
33 | - [Figure 1.12 - `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/srp/Vehicle.java)
34 | - [Figure 1.12 - `Engine` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/srp/Engine.java)
35 | - [Figure 1.12 - `VehicleComputer` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/srp/VehicleComputer.java)
36 | - open-closed principle (OCP)
37 | - [Example 1.5 - `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/Vehicle.java)
38 | - [Example 1.5 - `Truck` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/Truck.java)
39 | - [Example 1.6 - `Example1_6Main` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/Example1_6Main.java)
40 | - liskov substitution principle (LSP)
41 | - [Example 1.7 - `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/Vehicle.java)
42 | - [Example 1.7 - `CarWash` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/CarWash.java)
43 | - [Example 1.7 - `Car` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/Car.java)
44 | - [Example 1.7 - `SportCar` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/SportCar.java)
45 | - [Example 1.7 - `Example1_7Main.java` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/general/Example1_7Main.java)
46 | - interface segregation principle (ISP)
47 | - malicious
48 | - [Example 1.8 - `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_malicious/Vehicle.java)
49 | - [Example 1.8 - `Bike` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_malicious/Bike.java)
50 | - [Example 1.8 - `Car` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_malicious/Car.java)
51 | - [Example 1.8 - `Example1_8Main` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_malicious/Example1_8Main.java)
52 | - optimal
53 | - [Example 1.9 - `Vehicle` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_optimal/Vehicle.java)
54 | - [Example 1.9 - `Bike` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_optimal/Bike.java)
55 | - [Example 1.9 - `Car` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_optimal/Car.java)
56 | - [Example 1.9 - `HasEngine` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_optimal/HasEngine.java)
57 | - [Example 1.9 - `HasPedals` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_optimal/HasPedals.java)
58 | - [Example 1.9 - `Example1_8Main` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/spi_optimal/Example1_9Main.java)
59 | - dependency inversion principle (DIP)
60 | - [Example 1.10 - `Gerage` class](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/Chapter01/solid/dip/Garage.java)
61 |
62 | ### Runnable Examples:
63 | ```bash
64 | # Example 1.2:
65 | $ javac --release 17 --enable-preview -g -cp out/Chapter01/apie/ -sourcepath java -d out/Chapter01/apie ./Chapter01/apie/*.java
66 | $ java --enable-preview -cp out/Chapter01/apie Example1_2Main
67 |
68 | # Example 1.6 and Example 1.7
69 | $ javac --release 17 --enable-preview -g -cp out/Chapter01/solid/general/ -sourcepath java -d out/Chapter01/solid/general ./Chapter01/solid/general/*.java
70 | $ java --enable-preview -cp out/Chapter01/solid/general Example1_6Main
71 | $ java --enable-preview -cp out/Chapter01/solid/general Example1_7Main
72 |
73 | # Example 1.8: SPI - malicious
74 | $ javac --release 17 --enable-preview -g -cp out/Chapter01/solid/spi_malicious/ -sourcepath java -d out/Chapter01/solid/spi_malicious ./Chapter01/solid/spi_malicious/*.java
75 | $ java --enable-preview -cp out/Chapter01/solid/spi_malicious Example1_8Main
76 |
77 | # Example 1.9: SPI - optimal
78 | $ javac --release 17 --enable-preview -g -cp out/Chapter01/solid/spi_optimal/ -sourcepath java -d out/Chapter01/solid/spi_optimal ./Chapter01/solid/spi_optimal/*.java
79 | $ java --enable-preview -cp out/Chapter01/solid/spi_optimal Example1_9Main
80 |
--------------------------------------------------------------------------------
/Chapter01/apie/AbstractVehicle.java:
--------------------------------------------------------------------------------
1 | public abstract class AbstractVehicle implements VehicleInterface{
2 | abstract public void move();
3 | public void stop(){
4 | System.out.println("stopped...");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter01/apie/Bus.java:
--------------------------------------------------------------------------------
1 | public class Bus implements VehicleInterface{
2 | @Override
3 | public void move() {
4 | System.out.println("bus moves...");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter01/apie/Car.java:
--------------------------------------------------------------------------------
1 | // @start region="polymorphism_override"
2 | public class Car extends Vehicle {
3 | @Override
4 | public void move(){
5 | System.out.println("moving faster...");
6 | }
7 | }
8 | // @end
--------------------------------------------------------------------------------
/Chapter01/apie/CommonCar.java:
--------------------------------------------------------------------------------
1 | public class CommonCar extends AbstractVehicle{
2 | @Override
3 | public void move() {
4 | System.out.println("move slow...");
5 | }
6 | }
--------------------------------------------------------------------------------
/Chapter01/apie/Example1_2Main.java:
--------------------------------------------------------------------------------
1 | /**
2 | * The following executable class refers to:
3 | *
4 | * - Example 1.1
5 | *
- Example 1.2
6 | *
7 | *
8 | * Chapter 1: Getting into Software Design Patterns, Examining OOP and APIE
9 | * {@snippet file="Example1_2Main.java" region="encapsulation_example"}
10 | *
11 | *
12 | * - 1. Encapsulation
13 | * {@snippet file="Vehicle.java" region="vehicle_example"}
14 | *
15 | *
- 2. Inheritance
16 | *
- 3. Polymorphism
17 | * {@snippet file="Car.java" region="polymorphism_override"}
18 | *
- 4. Abstraction
19 | *
20 | *
21 | */
22 | public class Example1_2Main {
23 |
24 | public static void main(String[] args) {
25 | Vehicle vehicle = new Car();
26 | // @start region="encapsulation_example"
27 | vehicle.move();
28 | // @end
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Chapter01/apie/SportCar.java:
--------------------------------------------------------------------------------
1 | public class SportCar extends AbstractVehicle{
2 | @Override
3 | public void move() {
4 | System.out.println("move fast...");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter01/apie/Truck.java:
--------------------------------------------------------------------------------
1 | public class Truck implements VehicleInterface{
2 | @Override
3 | public void move() {
4 | System.out.println("truck moves...");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter01/apie/Vehicle.java:
--------------------------------------------------------------------------------
1 | // @start region="vehicle_example"
2 | public class Vehicle {
3 | public boolean moving;
4 | public void move(){
5 | this.moving = true;
6 | System.out.println("moving...");
7 | }
8 |
9 | public void stop(){
10 | this.moving = false;
11 | System.out.println("stopped...");
12 | }
13 | }
14 | // @end
--------------------------------------------------------------------------------
/Chapter01/apie/VehicleInterface.java:
--------------------------------------------------------------------------------
1 | public interface VehicleInterface {
2 | void move();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter01/solid/dip/Garage.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | interface Vehicle {}
5 | class Car implements Vehicle {}
6 | class SportCar extends Car {}
7 | class Truck implements Vehicle {}
8 | class Bus implements Vehicle {}
9 |
10 | public class Garage {
11 | private List parkingSpots = new ArrayList<>();
12 | public void park(Vehicle vehicle){
13 | parkingSpots.add(vehicle);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter01/solid/general/Car.java:
--------------------------------------------------------------------------------
1 | public class Car implements Vehicle{
2 | public void move(){}
3 | }
--------------------------------------------------------------------------------
/Chapter01/solid/general/CarWash.java:
--------------------------------------------------------------------------------
1 | public class CarWash {
2 | public void wash(Vehicle vehicle){}
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter01/solid/general/Example1_6Main.java:
--------------------------------------------------------------------------------
1 | import java.util.Arrays;
2 | import java.util.List;
3 |
4 | public class Example1_6Main {
5 | public static void main(String[] args) {
6 | List vehicles = Arrays.asList(new Truck(), new Car());
7 | vehicles.get(0).move();
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter01/solid/general/Example1_7Main.java:
--------------------------------------------------------------------------------
1 | public class Example1_7Main {
2 | public static void main(String[] args) {
3 | CarWash carWash = new CarWash();
4 | carWash.wash(new Car());
5 | carWash.wash(new SportCar());
6 | }
7 | }
--------------------------------------------------------------------------------
/Chapter01/solid/general/SportCar.java:
--------------------------------------------------------------------------------
1 | public class SportCar extends Car {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter01/solid/general/Truck.java:
--------------------------------------------------------------------------------
1 | public class Truck implements Vehicle {
2 | public void move(){}
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter01/solid/general/Vehicle.java:
--------------------------------------------------------------------------------
1 | public interface Vehicle {
2 | /**
3 | * Example 1.5 : does not contain the method move()
4 | * Example 1.6 : added abstract public method move()
5 | */
6 | void move();
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_malicious/Bike.java:
--------------------------------------------------------------------------------
1 | public class Bike implements Vehicle{
2 | private boolean moving;
3 | public void setMove(boolean moving) {
4 | this.moving = moving;
5 | }
6 | public boolean engineOn() {
7 | throw new IllegalArgumentException("not supported");
8 | }
9 | public boolean pedalsMove() {
10 | return moving;
11 | }
12 | }
--------------------------------------------------------------------------------
/Chapter01/solid/spi_malicious/Car.java:
--------------------------------------------------------------------------------
1 | public class Car implements Vehicle {
2 | private boolean moving;
3 | public void setMove(boolean moving) {
4 | this.moving = moving;
5 | }
6 | public boolean engineOn() {
7 | return moving;
8 | }
9 | public boolean pedalsMove() {
10 | throw new IllegalStateException("not supported");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_malicious/Example1_8Main.java:
--------------------------------------------------------------------------------
1 | public class Example1_8Main {
2 | public static void main(String[] args) {
3 | var car = new Car();
4 | var bike = new Bike();
5 |
6 | printIsMoving(new Car());
7 | printIsMoving(new Bike());
8 | }
9 |
10 | private static void printIsMoving(Vehicle v) {
11 | if (v instanceof Car) { System.out.println(v.engineOn()); }
12 | if(v instanceof Bike) { System.out.println(v.pedalsMove()); }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_malicious/Vehicle.java:
--------------------------------------------------------------------------------
1 | public interface Vehicle {
2 | void setMove(boolean moving);
3 | boolean engineOn();
4 | boolean pedalsMove();
5 | }
--------------------------------------------------------------------------------
/Chapter01/solid/spi_optimal/Bike.java:
--------------------------------------------------------------------------------
1 | public class Bike implements HasPedals, Vehicle {
2 | private boolean moving;
3 |
4 | public void setMove(boolean moving) {
5 | this.moving = moving;
6 | }
7 |
8 | public boolean pedalsMove() {
9 | return moving;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_optimal/Car.java:
--------------------------------------------------------------------------------
1 | public class Car implements HasEngine, Vehicle {
2 | private boolean moving;
3 |
4 | public void setMove(boolean moving) {
5 | this.moving = moving;
6 | }
7 |
8 | public boolean engineOn() {
9 | return moving;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_optimal/Example1_9Main.java:
--------------------------------------------------------------------------------
1 | public class Example1_9Main {
2 | public static void main(String[] args) {
3 | printIsMoving(new Car());
4 | printIsMoving(new Bike());
5 | }
6 |
7 |
8 | private static void printIsMoving(Vehicle v){
9 | // no access to internal state
10 | }
11 | private static void printIsMoving(Car c) {
12 | System.out.println(c.engineOn());
13 | }
14 | private static void printIsMoving(Bike b) {
15 | System.out.println(b.pedalsMove());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_optimal/HasEngine.java:
--------------------------------------------------------------------------------
1 | public interface HasEngine {
2 | boolean engineOn();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_optimal/HasPedals.java:
--------------------------------------------------------------------------------
1 | public interface HasPedals {
2 | boolean pedalsMove();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter01/solid/spi_optimal/Vehicle.java:
--------------------------------------------------------------------------------
1 | public interface Vehicle {
2 | void setMove(boolean moving);
3 | }
--------------------------------------------------------------------------------
/Chapter01/solid/srp/Engine.java:
--------------------------------------------------------------------------------
1 | class Engine {
2 | void start(){}
3 | void stop(){}
4 | }
--------------------------------------------------------------------------------
/Chapter01/solid/srp/Vehicle.java:
--------------------------------------------------------------------------------
1 | class Vehicle {
2 | private final Engine engine = new Engine();
3 | private final VehicleComputer vehicleComputer = new VehicleComputer();
4 | void move(){
5 | engine.start();
6 | vehicleComputer.lightsOn();
7 | }
8 | void stop(){
9 | engine.stop();
10 | vehicleComputer.lightsOff();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter01/solid/srp/VehicleComputer.java:
--------------------------------------------------------------------------------
1 | class VehicleComputer {
2 | void lightsOn(){}
3 | void lightsOff(){}
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter02/Figure_2_4_Program_Reading.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter02/Figure_2_4_Program_Reading.jfr
--------------------------------------------------------------------------------
/Chapter02/Jep323.java:
--------------------------------------------------------------------------------
1 | import java.util.function.Consumer;
2 | import java.util.stream.IntStream;
3 |
4 | /**
5 | * JEP-323: Local-Variable Syntax for Lambda Parameters
6 | * {@link https://openjdk.java.net/jeps/323}
7 | */
8 | public class Jep323 {
9 | public static void main(String[] args) {
10 | Consumer consumer = (var number) -> {
11 | var result = number + 1;
12 | System.out.println("result:" + result);
13 | };
14 | IntStream.of(1, 2, 3).boxed().forEach(consumer);
15 | }
16 | }
--------------------------------------------------------------------------------
/Chapter02/Jep361.java:
--------------------------------------------------------------------------------
1 | /**
2 | * JEP-361: Switch Expressions
3 | * {@link https://openjdk.java.net/jeps/361}
4 | */
5 | public class Jep361 {
6 | public static void main(String[] args) {
7 | var inputNumber = 42;
8 | String textNumber = switch (inputNumber){
9 | case 22,42 -> String.valueOf(inputNumber);
10 | default -> throw new RuntimeException("not allowed");
11 | };
12 | System.out.printf("""
13 | number:'%s'
14 | %n""", textNumber);
15 | }
16 | }
--------------------------------------------------------------------------------
/Chapter02/Jep394.java:
--------------------------------------------------------------------------------
1 | /**
2 | * JEP-394: Pattern Matching for instanceof
3 | * {@link https://openjdk.java.net/jeps/394}
4 | */
5 | public class Jep394 {
6 | public static void main(String[] args) {
7 | Object obj = "text";
8 | if(obj instanceof String s){
9 | System.out.println(s.toUpperCase());
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter02/Jep395.java:
--------------------------------------------------------------------------------
1 | /**
2 | * JEP-395: Records
3 | * {@link https://openjdk.java.net/jeps/395}
4 | */
5 | public class Jep395 {
6 | private record Example(int number, String text){
7 | private String getTogether(){
8 | return number + text;
9 | }
10 | }
11 |
12 | public static void main(String[] args) {
13 | var r1 = new Example(1, "text");
14 | var r2 = new Example(2, "text");
15 | System.out.println(r1.equals(r2));
16 | System.out.println(r1.getTogether());
17 | }
18 | }
--------------------------------------------------------------------------------
/Chapter02/Jep420.java:
--------------------------------------------------------------------------------
1 | /**
2 | * JEP-420: Pattern Matching for switch (Second Preview)
3 | * note: requires to have enabled preview features
4 | *
5 | * $javac --enable-preview --release 18 Jep420.java
6 | * $java --enable-preview Jep420
7 | *
8 | * {@link https://openjdk.java.net/jeps/420}
9 | */
10 | public class Jep420 {
11 | public static void main(String[] args) {
12 | Object variable = 42;
13 | String text = switch (variable){
14 | case Integer i -> "number"+i;
15 | default -> "text";
16 | };
17 | System.out.println(text);
18 | }
19 | }
--------------------------------------------------------------------------------
/Chapter02/MultiThreadedProgram.java:
--------------------------------------------------------------------------------
1 | public class MultiThreadedProgram {
2 | public static void main(String[] args) {
3 | var t = new Thread(() -> {
4 | while(true){System.out.println("Welcome Thread!");}
5 | });
6 | t.setDaemon(true);
7 | t.start();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter02/Program.java:
--------------------------------------------------------------------------------
1 | public class Program {
2 | public static void main(String... args){
3 | System.out.println("Hello Program!");
4 | }
5 | }
--------------------------------------------------------------------------------
/Chapter02/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
2 | ## Chapter 2 - discovering the java platform for design patterns examples
3 | #### Runnable Examples
4 | ```bash
5 | # Example 2.1:
6 | $ java ./Chapter02/Program.java
7 |
8 | # Example 2.12 and Example 2.13
9 | $ java ./Chapter02/StreamMain.java
10 |
11 | # Example 2.18: JPMS
12 | $ javac -d ./out/Chapter02/module-example ./Chapter02/module-example/module-info.java ./Chapter02/module-example/example/ExampleMain.java
13 | $ jar --create --file ./out/Chapter02/module-example.jar -C ./out/Chapter02/module-example .
14 | $ java --module-path ./out/Chapter02/module-example.jar --module module.example/example.ExampleMain
15 |
16 | # Example 2.20: JEP-323
17 | $ java ./Chapter02/Jep323.java
18 |
19 | # Example 2.21: JEP-361
20 | $ java ./Chapter02/Jep361.java
21 |
22 | # Example 2.22: JEP-394
23 | $ java ./Chapter02/Jep394.java
24 |
25 | # Example 2.23: JEP-395
26 | $ java ./Chapter02/Jep395.java
27 |
28 | # Example 2.24: JEP-409
29 | $ javac --release 17 --enable-preview -g -cp ./out/Chapter02/jep409 -sourcepath java -d ./out/Chapter02/jep409 ./Chapter02/jep409/*.java
30 | $ java --enable-preview -cp out/Chapter02/jep409 Jep409Main
31 |
32 | # Example 2.27: JEP-420
33 | $ javac --release 17 --enable-preview -g -d ./out/Chapter02 ./Chapter02/Jep420.java
34 | $ java --enable-preview -cp ./out/Chapter02 Jep420
35 |
36 | # Example 2.28:
37 | $ java ./Chapter02/MultiThreadedProgram.java
38 | ```
39 |
--------------------------------------------------------------------------------
/Chapter02/StreamMain.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 | import java.util.function.Predicate;
6 | import java.util.stream.Collectors;
7 | import java.util.stream.Stream;
8 |
9 | class StreamMain {
10 | public static void main(String[] args) {
11 |
12 | List list = Arrays.asList("one", "two", "forty_two");
13 | list.forEach(System.out::println);
14 |
15 | Predicate numberTest = new Predicate() {
16 | @Override
17 | public boolean test(Integer e) {
18 | return e > 2;
19 | }
20 | };
21 | String result = Stream.of(1,2,3, 42)
22 | //.filter(e -> e > 2) //Anonymous class example
23 | .filter(numberTest)
24 | .map(e -> "element" + e)
25 | .collect(Collectors.joining(","));
26 | System.out.println("result: " + result);
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Chapter02/jep409/Bus.java:
--------------------------------------------------------------------------------
1 | public final class Bus extends SlowEngine implements Vehicle {
2 | public String toString() {
3 | return "Bus{running=" + super.running + '}';
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter02/jep409/Car.java:
--------------------------------------------------------------------------------
1 | public non-sealed class Car extends NormalEngine implements Vehicle {
2 | public String toString(){
3 | return "Car{running="+ super.running +'}';
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter02/jep409/Jep409Main.java:
--------------------------------------------------------------------------------
1 | public class Jep409Main {
2 | public static void main(String[] args) {
3 | var superCar = new Car();
4 | var bus = new Bus();
5 | System.out.println(superCar);
6 | }
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter02/jep409/Motorbike.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Motorbike is not allowed to extend Vehicle
4 | */
5 | //public class Motorbike implements Vehicle {
6 | public class Motorbike {
7 | public void start() {}
8 |
9 | public void stop() {}
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter02/jep409/NormalEngine.java:
--------------------------------------------------------------------------------
1 | public abstract sealed class NormalEngine permits Car {
2 | protected boolean running;
3 |
4 | public NormalEngine() {
5 | this.running = false;
6 | }
7 |
8 | public void start() {
9 | System.out.println("NormalEngine, start");
10 | this.running = true;
11 | }
12 |
13 | public void stop() {
14 | System.out.println("NormalEngine, stop");
15 | this.running = false;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter02/jep409/SlowEngine.java:
--------------------------------------------------------------------------------
1 | public abstract sealed class SlowEngine permits Bus {
2 | protected boolean running;
3 | public SlowEngine(){
4 | this.running = false;
5 | }
6 |
7 | public void start(){
8 | System.out.println("SlowEngine, start");
9 | this.running = true;
10 | }
11 |
12 | public void stop(){
13 | System.out.println("SlowEngine, stop");
14 | this.running = false;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter02/jep409/SuperCar.java:
--------------------------------------------------------------------------------
1 | public class SuperCar extends Car{
2 | public String toString(){
3 | return "SuperCar{running="+ super.running +'}';
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter02/jep409/Vehicle.java:
--------------------------------------------------------------------------------
1 | public sealed interface Vehicle permits Car, Bus {
2 | void start();
3 | void stop();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter02/module-example.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter02/module-example.jar
--------------------------------------------------------------------------------
/Chapter02/module-example/example/ExampleMain.java:
--------------------------------------------------------------------------------
1 | package example;
2 |
3 | public class ExampleMain {
4 | public static void main(String[] args) {
5 | System.out.println("Welcome to JMPS!");
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter02/module-example/module-info.java:
--------------------------------------------------------------------------------
1 | module module.example {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter03/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
2 | ## Chapter 3 - creational patterns examples
3 | ```bash
4 | # Factory Method: creating instances
5 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/fm -sourcepath java -d out/Chapter03/fm ./Chapter03/factory_method/*.java
6 | $ java --enable-preview -cp out/Chapter03/fm FactoryMethodMain
7 | $ java --enable-preview -cp out/Chapter03/fm -XX:StartFlightRecording=filename=FactoryMethod.jfr,dumponexit-true,settings=profile FactoryMethodMain
8 |
9 | # Abstract Factory: instancise proper factory to create desired instances
10 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/af -sourcepath java -d out/Chapter03/af ./Chapter03/abstract_factory/*.java
11 | $ java --enable-preview -cp out/Chapter03/af AbstractFactoryMain
12 |
13 | # Builder
14 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/builder -sourcepath java -d out/Chapter03/builder ./Chapter03/builder/*.java
15 | $ java --enable-preview -cp out/Chapter03/builder BuilderMain
16 |
17 | # Prototype
18 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/prototype -sourcepath java -d out/Chapter03/prototype ./Chapter03/prototype/*.java
19 | $ java --enable-preview -cp out/Chapter03/prototype PrototypeMain
20 |
21 | # Singleton
22 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/singleton -sourcepath java -d out/Chapter03/singleton ./Chapter03/singleton/*.java
23 | $ java --enable-preview -cp out/Chapter03/singleton SingletonMain
24 |
25 |
26 | # Object Pool
27 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/object_pool -sourcepath java -d out/Chapter03/object_pool ./Chapter03/object_pool/*.java
28 | $ java --enable-preview -cp out/Chapter03/object_pool ObjectPoolMain
29 |
30 | # Lazy Initialization
31 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/lazy_initialization -sourcepath java -d out/Chapter03/lazy_initialization ./Chapter03/lazy_initialization/*.java
32 | $ java --enable-preview -cp out/Chapter03/lazy_initialization LazyInitializationMain
33 |
34 | # Dependency Injection
35 | $ javac --release 17 --enable-preview -g -cp out/Chapter03/dependency_injection -sourcepath java -d out/Chapter03/dependency_injection ./Chapter03/dependency_injection/*.java
36 | $ java --enable-preview -cp out/Chapter03/dependency_injection DependencyInjectionMain
37 |
38 | ### it is required to have present the service providers configuration in the classpath
39 | $ cp -R Chapter03/dependency_injection/META-INF out/Chapter03/dependency_injection
40 | $ java --enable-preview -cp out/Chapter03/dependency_injection DependencyInjectionServiceLoaderMain
41 | ```
42 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/AbstractFactory.java:
--------------------------------------------------------------------------------
1 | abstract class AbstractFactory {
2 | abstract Vehicle createVehicle(String type);
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/AbstractFactoryMain.java:
--------------------------------------------------------------------------------
1 |
2 | public class AbstractFactoryMain {
3 | public static void main(String[] args) {
4 | System.out.println("Pattern Abstract Factory: Vehicle Factory 1...");
5 | AbstractFactory carFactory = FactoryProvider.getFactory("car");
6 | Vehicle slowCar = carFactory.createVehicle("slow");
7 | slowCar.move();
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/CarFactory.java:
--------------------------------------------------------------------------------
1 | class CarFactory extends AbstractFactory{
2 | @Override
3 | Vehicle createVehicle(String type) {
4 | return switch (type) {
5 | case "slow" -> new SlowVehicle();
6 | case "fast" -> new FastVehicle();
7 | default -> throw new IllegalArgumentException("not implemented");
8 | };
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/FactoryProvider.java:
--------------------------------------------------------------------------------
1 | final class FactoryProvider {
2 | private FactoryProvider(){}
3 | static AbstractFactory getFactory(String type){
4 | return switch (type) {
5 | case "car" -> new CarFactory();
6 | case "truck" -> new TruckFactory();
7 | default -> throw new IllegalArgumentException("""
8 | this is %s""".formatted(type));
9 | };
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/FastCar.java:
--------------------------------------------------------------------------------
1 | class FastCar implements Vehicle {
2 | @Override
3 | public void move() {
4 | System.out.println("fast car, move");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/HeavyTruck.java:
--------------------------------------------------------------------------------
1 | class HeavyTruck implements Vehicle{
2 | @Override
3 | public void move() {
4 | System.out.println("heavy truck, move");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/LightTruck.java:
--------------------------------------------------------------------------------
1 | class LightTruck implements Vehicle {
2 | @Override
3 | public void move() {
4 | System.out.println("light truck, move");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/SlowCar.java:
--------------------------------------------------------------------------------
1 | class SlowCar implements Vehicle {
2 | @Override
3 | public void move() {
4 | System.out.println("slow car, move");
5 | }
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/TruckFactory.java:
--------------------------------------------------------------------------------
1 | class TruckFactory extends AbstractFactory {
2 | @Override
3 | Vehicle createVehicle(String type) {
4 | return switch(type) {
5 | case "heavy" -> new HeavyTruck();
6 | case "light" -> new LightTruck();
7 | default -> throw new IllegalArgumentException("not implemented");
8 | };
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter03/abstract_factory/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void move();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter03/builder/BuilderMain.java:
--------------------------------------------------------------------------------
1 | class BuilderMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Builder: building vehicles ");
4 |
5 | var slowVehicle = VehicleBuilder.buildSlowVehicle();
6 | var fastVehicle = new FastVehicle.Builder()
7 | .addCabin("cabin")
8 | .addEngine("Engine")
9 | .build();
10 | var superVehicle = new SuperVehicle.Builder()
11 | .addCabin("super_cabin")
12 | .addEngine("super_engine")
13 | .build();
14 |
15 | slowVehicle.parts();
16 | fastVehicle.parts();
17 | System.out.println(superVehicle);
18 | superVehicle.parts();
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/Chapter03/builder/FastVehicle.java:
--------------------------------------------------------------------------------
1 | class FastVehicle implements Vehicle {
2 |
3 | final static class Builder {
4 | private Part engine;
5 | private Part cabin;
6 | Builder(){}
7 |
8 | Builder addEngine(String e){
9 | this.engine = new StandardPart(e);
10 | return this;
11 | }
12 |
13 | Builder addCabin(String c){
14 | this.cabin = new RecordPart(c);
15 | return this;
16 | }
17 |
18 | FastVehicle build(){
19 | return new FastVehicle(engine, cabin);
20 | }
21 | }
22 |
23 | private final Part engine;
24 | private final Part cabin;
25 |
26 | FastVehicle(Part engine, Part cabin){
27 | this.engine = engine;
28 | this.cabin = cabin;
29 | }
30 |
31 | @Override
32 | public void move() {
33 | System.out.println("FastVehicle, move");
34 |
35 | }
36 |
37 | @Override
38 | public void parts() {
39 | System.out.println("FastVehicle,engine: " + engine);
40 | System.out.println("FastVehicle,cabin: " + cabin);
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Chapter03/builder/Part.java:
--------------------------------------------------------------------------------
1 | interface Part{
2 | String name();
3 | }
--------------------------------------------------------------------------------
/Chapter03/builder/RecordPart.java:
--------------------------------------------------------------------------------
1 | record RecordPart(String name) implements Part{
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter03/builder/SlowVehicle.java:
--------------------------------------------------------------------------------
1 | class SlowVehicle implements Vehicle{
2 | private final Part engine;
3 | private final Part cabin;
4 |
5 | SlowVehicle(Part engine, Part cabin){
6 | this.engine = engine;
7 | this.cabin = cabin;
8 | }
9 |
10 | @Override
11 | public void move() {
12 | System.out.println("SlowVehicle, move");
13 | }
14 |
15 | @Override
16 | public void parts() {
17 | System.out.println("SlowVehicle,engine: " + engine);
18 | System.out.println("SlowVehicle,cabin: " + cabin);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Chapter03/builder/StandardPart.java:
--------------------------------------------------------------------------------
1 | class StandardPart implements Part {
2 |
3 | private final String name;
4 |
5 | StandardPart(String name){
6 | this.name = name;
7 | }
8 |
9 | @Override
10 | public String name() {
11 | return null;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter03/builder/SuperVehicle.java:
--------------------------------------------------------------------------------
1 | record SuperVehicle(Part engine, Part cabin) implements Vehicle{
2 |
3 | static final class Builder {
4 | private Part engine;
5 | private Part cabin;
6 | Builder(){}
7 |
8 | Builder addEngine(String type) {
9 | this.engine = new RecordPart(type);
10 | return this;
11 | }
12 |
13 | Builder addCabin(String type) {
14 | this.cabin = new RecordPart(type);
15 | return this;
16 | }
17 |
18 | Vehicle build(){
19 | return new SuperVehicle(this);
20 | }
21 | }
22 |
23 | private SuperVehicle(Builder builder) {
24 | this(builder.engine, builder.cabin);
25 | }
26 |
27 | @Override
28 | public void move() {
29 | System.out.println("SuperVehicle, move");
30 | }
31 |
32 | @Override
33 | public void parts() {
34 | System.out.println("SuperVehicle,engine: " + engine);
35 | System.out.println("SuperVehicle,cabin: " + cabin);
36 | }
37 | }
--------------------------------------------------------------------------------
/Chapter03/builder/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void move();
3 | void parts();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter03/builder/VehicleBuilder.java:
--------------------------------------------------------------------------------
1 | final class VehicleBuilder {
2 | static Vehicle buildSlowVehicle(){
3 | var engine = new RecordPart("engine");
4 | var cabin = new StandardPart("cabin");
5 | return new SlowVehicle(engine, cabin);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/DependencyInjectionMain.java:
--------------------------------------------------------------------------------
1 | final class DependencyInjectionMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Dependency Injection: vehicle and engine");
4 | EngineServiceProvider.addEngine(new FastEngine("sport"));
5 |
6 | Engine engine = EngineServiceProvider.getEngineByType("sport");
7 | Vehicle vehicle = new SportVehicle(engine);
8 | vehicle.move();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/DependencyInjectionServiceLoaderMain.java:
--------------------------------------------------------------------------------
1 | import java.util.ServiceLoader;
2 |
3 | class DependencyInjectionServiceLoaderMain {
4 | public static void main(String[] args) {
5 | System.out.println("Pattern Dependency Injection Service Loader: vehicle and engine");
6 | ServiceLoader engineService = ServiceLoader.load(Engine.class);
7 | Engine engine = engineService.findFirst().orElseThrow();
8 | Vehicle vehicle = new SportVehicle(engine);
9 | vehicle.move();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/Engine.java:
--------------------------------------------------------------------------------
1 | interface Engine {
2 | void start();
3 | boolean isStarted();
4 | void run();
5 |
6 | String type();
7 | }
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/EngineServiceLoader.java:
--------------------------------------------------------------------------------
1 | public class EngineServiceLoader implements Engine{
2 |
3 | public EngineServiceLoader(){}
4 |
5 | @Override
6 | public void start() {
7 | System.out.println("EngineServiceLoader, start");
8 | }
9 |
10 | @Override
11 | public boolean isStarted() {
12 | return false;
13 | }
14 |
15 | @Override
16 | public void run() {
17 |
18 | }
19 |
20 | @Override
21 | public String type() {
22 | return null;
23 | }
24 | }
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/EngineServiceProvider.java:
--------------------------------------------------------------------------------
1 | import java.util.HashMap;
2 | import java.util.Map;
3 |
4 | final class EngineServiceProvider {
5 | private static final Map ENGINES = new HashMap<>();
6 |
7 | private EngineServiceProvider(){}
8 |
9 | static void addEngine(Engine e){
10 | ENGINES.put(e.type(), e);
11 | }
12 |
13 | static Engine getEngineByType(String t){
14 | return ENGINES.values().stream()
15 | .filter(e -> e.type().equals(t))
16 | .findFirst().orElseThrow(IllegalArgumentException::new);
17 | }
18 | }
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/FastEngine.java:
--------------------------------------------------------------------------------
1 | class FastEngine implements Engine{
2 | private final String type;
3 | private boolean started;
4 |
5 | public FastEngine(String type) {
6 | this.type = type;
7 | }
8 |
9 | @Override
10 | public void start() {
11 | System.out.println("FastEngine, started");
12 | started = true;
13 | }
14 |
15 | @Override
16 | public boolean isStarted() {
17 | return started;
18 | }
19 |
20 | @Override
21 | public void run() {
22 | if(started){
23 | System.out.println("FastEngine, run");
24 | } else {
25 | throw new IllegalStateException("FastEngine, not started");
26 | }
27 | }
28 |
29 | @Override
30 | public String type() {
31 | return type;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/META-INF/services/Engine:
--------------------------------------------------------------------------------
1 | EngineServiceLoader
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/SportVehicle.java:
--------------------------------------------------------------------------------
1 | class SportVehicle implements Vehicle{
2 |
3 | private final Engine engine;
4 |
5 | SportVehicle(Engine e) {
6 | this.engine = e;
7 | }
8 |
9 | @Override
10 | public void move() {
11 | if(!engine.isStarted()){
12 | engine.start();
13 | }
14 | engine.run();
15 | System.out.println("SportCar, move");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter03/dependency_injection/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void move();
3 | }
--------------------------------------------------------------------------------
/Chapter03/factory_method/FactoryMethodMain.java:
--------------------------------------------------------------------------------
1 | final class FactoryMethodMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Factory Method: Vehicle Factory 2");
4 | var sportCar = VehicleFactory.produce("sport");
5 | System.out.println("sport-car:" + sportCar);
6 | sportCar.move();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter03/factory_method/SportCar.java:
--------------------------------------------------------------------------------
1 | record SportCar(String type) implements Vehicle {
2 | @Override
3 | public void move() {
4 | System.out.println("""
5 | SportCar, type:'%s', move""".formatted(type));
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter03/factory_method/SuvCar.java:
--------------------------------------------------------------------------------
1 | record SuvCar(String type) implements Vehicle {
2 | @Override
3 | public void move() {
4 | System.out.println("""
5 | SuvCar, type:'%s', move""".formatted(type));
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter03/factory_method/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void move();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter03/factory_method/VehicleFactory.java:
--------------------------------------------------------------------------------
1 | final class VehicleFactory {
2 | private VehicleFactory(){}
3 | static Vehicle produce(String type){
4 | return switch (type) {
5 | case "sport" -> new SportCar("porsche 911");
6 | case "suv" -> new SuvCar("skoda kodiaq");
7 | default -> throw new IllegalArgumentException("""
8 | not implemented type:'%s'
9 | """.formatted(type));
10 |
11 | };
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter03/lazy_initialization/LazyInitializationMain.java:
--------------------------------------------------------------------------------
1 | class LazyInitializationMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Lazy Initialization: lazy vehicles");
4 |
5 | var vehicleProvider = new VehicleProvider();
6 | var truck1 = vehicleProvider.getVehicleByType("truck");
7 | vehicleProvider.printStatus();
8 | truck1.move();
9 | var car1 = vehicleProvider.getVehicleByType("car");
10 | var car2 = vehicleProvider.getVehicleByType("car");
11 | vehicleProvider.printStatus();
12 | car1.move();
13 | car2.move();
14 | System.out.println("ca1==car2: " + (car1.equals(car2)));
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter03/lazy_initialization/LazyVehicle.java:
--------------------------------------------------------------------------------
1 | record LazyVehicle(String type) implements Vehicle{
2 | @Override
3 | public void move() {
4 | System.out.println("LazyVehicle, move, type:" + type);
5 | }
6 | }
--------------------------------------------------------------------------------
/Chapter03/lazy_initialization/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void move();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter03/lazy_initialization/VehicleProvider.java:
--------------------------------------------------------------------------------
1 | import java.util.HashMap;
2 | import java.util.Map;
3 |
4 | final class VehicleProvider {
5 |
6 | private Vehicle truck;
7 | private Vehicle car;
8 |
9 | VehicleProvider() {
10 | }
11 |
12 | Vehicle getVehicleByType(String type){
13 |
14 | switch(type){
15 | case "car":
16 | if(car == null){
17 | System.out.println("lazy car created");
18 | car = new LazyVehicle(type);
19 |
20 | }
21 | return car;
22 | case "truck":
23 | if(truck == null){
24 | System.out.println("lazy truck created");
25 | truck = new LazyVehicle(type);
26 | }
27 | return truck;
28 | default:
29 | throw new IllegalArgumentException("not implemented");
30 | }
31 |
32 | }
33 |
34 | void printStatus(){
35 | System.out.println("status, truck:" + truck);
36 | System.out.println("status, car:" + car);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Chapter03/object_pool/AbstractGaragePool.java:
--------------------------------------------------------------------------------
1 | import java.util.HashSet;
2 | import java.util.Set;
3 | import java.util.stream.Collectors;
4 |
5 | abstract class AbstractGaragePool {
6 | private final Set available = new HashSet<>();
7 | private final Set inUse = new HashSet<>();
8 |
9 | protected abstract T buyVehicle();
10 |
11 | synchronized T driveVehicle() {
12 | if (available.isEmpty()) {
13 | available.add(buyVehicle());
14 | }
15 | var instance = available.iterator().next();
16 | available.remove(instance);
17 | inUse.add(instance);
18 | return instance;
19 | }
20 |
21 | synchronized void returnVehicle(T instance) {
22 | System.out.println("returned vehicle, vin:" + instance.getVin());
23 | inUse.remove(instance);
24 | available.add(instance);
25 | }
26 |
27 | void printStatus() {
28 | var availableVins = available.stream().map(Vehicle::getVin).collect(Collectors.toList());
29 | var inUseVins = inUse.stream().map(Vehicle::getVin).collect(Collectors.toList());
30 | System.out.printf("Garage Pool vehicles available=%d[%s] inUse=%d[%s]%n",
31 | available.size(), availableVins, inUse.size(), inUseVins);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Chapter03/object_pool/ObjectPoolMain.java:
--------------------------------------------------------------------------------
1 | class ObjectPoolMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Object Pool: vehicle garage");
4 | var garage = new PooledVehicleGarage();
5 | var vehicle1 = garage.driveVehicle();
6 | var vehicle2 = garage.driveVehicle();
7 | var vehicle3 = garage.driveVehicle();
8 | vehicle1.move();
9 | vehicle2.move();
10 | vehicle3.move();
11 | garage.returnVehicle(vehicle1);
12 | garage.returnVehicle(vehicle3);
13 | garage.printStatus();
14 | var vehicle4 = garage.driveVehicle();
15 | var vehicle5 = garage.driveVehicle();
16 | vehicle4.move();
17 | vehicle5.move();
18 | garage.printStatus();
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Chapter03/object_pool/PooledVehicle.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.atomic.AtomicInteger;
2 |
3 | class PooledVehicle implements Vehicle{
4 | private static final AtomicInteger COUNTER = new AtomicInteger();
5 |
6 | private final int vin;
7 | PooledVehicle() {
8 | this.vin = COUNTER.incrementAndGet();
9 | }
10 |
11 |
12 | @Override
13 | public int getVin(){
14 | return vin;
15 | }
16 |
17 | @Override
18 | public void move(){
19 | System.out.println("PooledVehicle, move, vin=" + vin);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Chapter03/object_pool/PooledVehicleGarage.java:
--------------------------------------------------------------------------------
1 | final class PooledVehicleGarage extends AbstractGaragePool{
2 |
3 | @Override
4 | protected PooledVehicle buyVehicle() {
5 | return new PooledVehicle();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter03/object_pool/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | int getVin();
3 | void move();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter03/prototype/FastCar.java:
--------------------------------------------------------------------------------
1 | final class FastCar extends Vehicle {
2 |
3 | FastCar(){
4 | super("fast car");
5 | }
6 |
7 | @Override
8 | void move() {
9 | System.out.println("""
10 | %s, move""".formatted(type));
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter03/prototype/PrototypeMain.java:
--------------------------------------------------------------------------------
1 | class PrototypeMain {
2 |
3 | public static void main(String[] args) {
4 | System.out.println("Pattern Prototype: vehicle prototype 1");
5 | Vehicle fastCar1 = VehicleCache.getVehicle("fast-car");
6 | Vehicle fastCar2 = VehicleCache.getVehicle("fast-car");
7 | fastCar1.move();
8 | fastCar2.move();
9 |
10 | System.out.println("equals : " + (fastCar1.equals(fastCar2)));
11 | System.out.println("fastCar1:" + fastCar1);
12 | System.out.println("fastCar2:" + fastCar2);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter03/prototype/SlowCar.java:
--------------------------------------------------------------------------------
1 | class SlowCar extends Vehicle {
2 | SlowCar(){
3 | super("slow car");
4 | }
5 |
6 | @Override
7 | void move() {
8 | System.out.println("""
9 | %s, move""".formatted(type));
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter03/prototype/Vehicle.java:
--------------------------------------------------------------------------------
1 | abstract class Vehicle implements Cloneable{
2 | protected final String type;
3 |
4 |
5 | Vehicle(String t){
6 | this.type = t;
7 | }
8 |
9 | abstract void move();
10 |
11 | @Override
12 | protected Object clone() {
13 | Object clone = null;
14 | try{
15 | clone = super.clone();
16 | } catch (CloneNotSupportedException e){
17 | System.err.println("""
18 | error: %s""".formatted(e));
19 | }
20 | return clone;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter03/prototype/VehicleCache.java:
--------------------------------------------------------------------------------
1 | import java.util.Map;
2 |
3 | final class VehicleCache {
4 |
5 | private static final Map map = Map.of("fast-car", new FastVehicle(), "slow-car", new SlowVehicle());
6 |
7 | private VehicleCache(){}
8 | static Vehicle getVehicle(String type){
9 | Vehicle vehicle = map.get(type);
10 | if(vehicle == null) throw new IllegalArgumentException("not allowed:" + type);
11 | return (Vehicle) vehicle.clone();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter03/singleton/Engine.java:
--------------------------------------------------------------------------------
1 | interface Engine {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter03/singleton/OnlyEngine.java:
--------------------------------------------------------------------------------
1 | class OnlyEngine implements Engine{
2 | private static OnlyEngine INSTANCE;
3 | static OnlyEngine getInstance(){
4 | if(INSTANCE == null){
5 | INSTANCE = new OnlyEngine();
6 | }
7 | return INSTANCE;
8 | }
9 | private OnlyEngine(){}
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter03/singleton/OnlyEngineEnum.java:
--------------------------------------------------------------------------------
1 | enum OnlyEngineEnum implements Engine {
2 | INSTANCE
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter03/singleton/OnlyVehicle.java:
--------------------------------------------------------------------------------
1 | class OnlyVehicle {
2 |
3 | private static OnlyVehicle INSTANCE = new OnlyVehicle();
4 | static OnlyVehicle getInstance(){
5 | return INSTANCE;
6 | }
7 |
8 | private final Engine engine;
9 |
10 | private OnlyVehicle(){
11 | this.engine = OnlyEngine.getInstance();
12 | //this.engine = OnlyEngineEnum.INSTANCE;
13 | }
14 |
15 | void move(){
16 | System.out.println("OnlyVehicle, move");
17 | }
18 |
19 | Engine getEngine(){
20 | return engine;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Chapter03/singleton/SingletonMain.java:
--------------------------------------------------------------------------------
1 | final class SingletonMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Singleton: only one engine");
4 | var engine = OnlyEngine.getInstance();
5 | var vehicle = OnlyVehicle.getInstance();
6 |
7 | vehicle.move();
8 | System.out.println("""
9 | OnlyEngine:'%s', equals with vehicle:'%s'"""
10 | .formatted(engine, (vehicle.getEngine().equals(engine))));
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter04/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
2 | ## Chapter 4 - structural pattern examples
3 | ```bash
4 | # Adapter
5 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/adapter -sourcepath java -d out/Chapter04/adapter ./Chapter04/adapter/*.java
6 | $ java --enable-preview -cp out/Chapter04/adapter AdapterMain
7 |
8 | # Bridge
9 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/bridge -sourcepath java -d out/Chapter04/bridge ./Chapter04/bridge/*.java
10 | $ java --enable-preview -cp out/Chapter04/bridge BridgeMain
11 |
12 | # Composite
13 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/composite -sourcepath java -d out/Chapter04/composite ./Chapter04/composite/*.java
14 | $ java --enable-preview -cp out/Chapter04/composite CompositeMain
15 |
16 | # Decorator
17 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/decorator -sourcepath java -d out/Chapter04/decorator ./Chapter04/decorator/*.java
18 | $ java --enable-preview -cp out/Chapter04/decorator DecoratorMain
19 |
20 | # Facade
21 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/facade -sourcepath java -d out/Chapter04/facade ./Chapter04/facade/*.java
22 | $ java --enable-preview -cp out/Chapter04/facade FacadeMain
23 |
24 | # Filter
25 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/filter -sourcepath java -d out/Chapter04/filter ./Chapter04/filter/*.java
26 | $ java --enable-preview -cp out/Chapter04/filter FilterMain
27 |
28 | # Flyweight
29 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/flyweight -sourcepath java -d out/Chapter04/flyweight ./Chapter04/flyweight/*.java
30 | $ java --enable-preview -cp out/Chapter04/flyweight FlyweightMain
31 |
32 | # Front controller
33 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/front_controller -sourcepath java -d out/Chapter04/front_controller ./Chapter04/front_controller/*.java
34 | $ java --enable-preview -cp out/Chapter04/front_controller FrontControllerMain
35 |
36 | # Marker
37 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/marker -sourcepath java -d out/Chapter04/marker ./Chapter04/marker/*.java
38 | $ java --enable-preview -cp out/Chapter04/marker MarkerMain
39 |
40 | # Module
41 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/module -sourcepath java -d out/Chapter04/module ./Chapter04/module/*.java
42 | $ java --enable-preview -cp out/Chapter04/module ModuleMain
43 |
44 | # Proxy
45 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/proxy -sourcepath java -d out/Chapter04/proxy ./Chapter04/proxy/*.java
46 | $ java --enable-preview -cp out/Chapter04/proxy ProxyMain
47 |
48 | # Twin
49 | $ javac --release 17 --enable-preview -g -cp out/Chapter04/twin -sourcepath java -d out/Chapter04/twin ./Chapter04/twin/*.java
50 | $ java --enable-preview -cp out/Chapter04/twin TwinMain
51 | ```
52 |
--------------------------------------------------------------------------------
/Chapter04/adapter/AdapterMain.java:
--------------------------------------------------------------------------------
1 | class AdapterMain {
2 | public static void main(String[] args) {
3 | System.out.println("Adapter Pattern: engines");
4 | var electricEngine = new ElectricEngine();
5 | var enginePetrol = new PetrolEngine();
6 | var vehicleElectric = new Vehicle(electricEngine);
7 | var vehiclePetrol = new Vehicle(enginePetrol);
8 |
9 | vehicleElectric.drive();
10 | vehicleElectric.refuel();
11 | vehiclePetrol.drive();
12 | vehiclePetrol.refuel();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter04/adapter/ElectricEngine.java:
--------------------------------------------------------------------------------
1 | final class ElectricEngine implements Engine{
2 | @Override
3 | public void run() {
4 | System.out.println("ElectricEngine, run");
5 | }
6 |
7 | @Override
8 | public void tank() {
9 | System.out.println("ElectricEngine, recharging");
10 | }
11 |
12 | public void checkPlug(){
13 | System.out.println("ElectricEngine, check plug");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter04/adapter/Engine.java:
--------------------------------------------------------------------------------
1 | sealed interface Engine permits ElectricEngine, PetrolEngine {
2 | void run();
3 | void tank();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter04/adapter/PetrolEngine.java:
--------------------------------------------------------------------------------
1 | final class PetrolEngine implements Engine {
2 | @Override
3 | public void run() {
4 | System.out.println("PetrolEngine, run");
5 | }
6 |
7 | @Override
8 | public void tank() {
9 | System.out.println("PetrolEngine, tank");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter04/adapter/Vehicle.java:
--------------------------------------------------------------------------------
1 | class Vehicle {
2 | private final Engine engine;
3 |
4 | Vehicle(Engine engine) {
5 | this.engine = engine;
6 | }
7 |
8 | public void drive(){
9 | System.out.println("Vehicle, drive");
10 | engine.run();
11 | }
12 |
13 | public void refuel(){
14 | System.out.println("Vehicle, stop");
15 | switch (engine){
16 | case ElectricEngine de -> {
17 | System.out.println("Vehicle needs recharge");
18 | de.checkPlug();
19 | de.tank();
20 | }
21 | case PetrolEngine pe -> {
22 | System.out.println("Vehicle needs petrol");
23 | pe.tank();
24 |
25 | }
26 | default -> throw new IllegalStateException("Vehicle has no engine");
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Chapter04/bridge/BridgeMain.java:
--------------------------------------------------------------------------------
1 | class BridgeMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Bridge, vehicle engines...");
4 | Vehicle sportVehicle = new SportVehicle(new PetrolEngine(), 911);
5 | Vehicle pickupVehicle = new PickupVehicle(new DieselEngine(), 300);
6 |
7 | sportVehicle.drive();
8 | sportVehicle.stop();
9 |
10 | pickupVehicle.drive();
11 | pickupVehicle.stop();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter04/bridge/DieselEngine.java:
--------------------------------------------------------------------------------
1 | class DieselEngine implements Engine{
2 | @Override
3 | public void turnOn() {
4 | System.out.println("DieselEngine, on");
5 | }
6 |
7 | @Override
8 | public void turnOff() {
9 | System.out.println("DieselEngine, off");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter04/bridge/Engine.java:
--------------------------------------------------------------------------------
1 | interface Engine {
2 | void turnOn();
3 | void turnOff();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter04/bridge/PetrolEngine.java:
--------------------------------------------------------------------------------
1 | class PetrolEngine implements Engine{
2 | @Override
3 | public void turnOn() {
4 | System.out.println("PetrolEngine, on");
5 | }
6 |
7 | @Override
8 | public void turnOff() {
9 | selfCheck();
10 | System.out.println("PetrolEngine, off");
11 | }
12 |
13 | private void selfCheck(){
14 | System.out.println("PetrolEngine, self check");
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter04/bridge/PickupVehicle.java:
--------------------------------------------------------------------------------
1 | final class PickupVehicle extends Vehicle{
2 | private final int horsePowers;
3 |
4 | public PickupVehicle(Engine engine, int horsePowers) {
5 | super("pick-car", engine);
6 | this.horsePowers = horsePowers;
7 | }
8 |
9 | @Override
10 | void drive() {
11 | System.out.println("PickupVehicle, starting engine");
12 | startEngine();
13 | System.out.println("PickupVehicle, engine started, hp:" + horsePowers);
14 | }
15 |
16 | @Override
17 | void stop() {
18 | System.out.println("PickupVehicle, stopping engine");
19 | stopEngine();
20 | System.out.println("PickupVehicle, engine stopped");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter04/bridge/SportVehicle.java:
--------------------------------------------------------------------------------
1 | final class SportVehicle extends Vehicle{
2 | private final int horsePowers;
3 |
4 | public SportVehicle(Engine engine, int horsePowers) {
5 | super("sport-car", engine);
6 | this.horsePowers = horsePowers;
7 | }
8 |
9 | @Override
10 | void drive() {
11 | System.out.println("SportVehicle, starting engine");
12 | startEngine();
13 | System.out.println("SportVehicle, engine started, hp:" + horsePowers);
14 | }
15 |
16 | @Override
17 | void stop() {
18 | System.out.println("SportVehicle, stopping engine");
19 | stopEngine();
20 | System.out.println("SportVehicle, engine stopped");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter04/bridge/Vehicle.java:
--------------------------------------------------------------------------------
1 | abstract class Vehicle {
2 |
3 | private final String type;
4 | private final Engine engine;
5 |
6 | protected Vehicle(String type, Engine engine) {
7 | this.type = type;
8 | this.engine = engine;
9 | }
10 |
11 | abstract void drive();
12 |
13 | abstract void stop();
14 |
15 | void startEngine(){
16 | engine.turnOn();
17 | }
18 |
19 | void stopEngine(){
20 | engine.turnOff();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter04/composite/CompositeMain.java:
--------------------------------------------------------------------------------
1 | class CompositeMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Composite, vehicle parts...");
4 | var fastVehicle = new SportVehicle("sport");
5 | var engine = new VehiclePart("fast-engine");
6 | engine.addPart(new VehiclePart("cylinder-head"));
7 | var breaks = new VehiclePart("super-breaks");
8 | var transmission = new VehiclePart("automatic-transmission");
9 | fastVehicle.addPart(engine);
10 | fastVehicle.addPart(breaks);
11 | fastVehicle.addPart(transmission);
12 | fastVehicle.printParts();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter04/composite/SportVehicle.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | class SportVehicle implements Vehicle {
5 | private final String type;
6 | private final List parts;
7 |
8 | SportVehicle(String type) {
9 | this.type = type;
10 | this.parts = new ArrayList<>();
11 | }
12 |
13 | @Override
14 | public void addPart(VehiclePart p) {
15 | this.parts.add(p);
16 | }
17 |
18 | @Override
19 | public void printParts() {
20 | System.out.printf("""
21 | SportCar, type'%s', parts:'%s'%n""", type, parts);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Chapter04/composite/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle> extends VehicleElement {
2 | void printParts();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter04/composite/VehicleElement.java:
--------------------------------------------------------------------------------
1 | public interface VehicleElement> {
2 | void addPart(T e);
3 |
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter04/composite/VehiclePart.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | class VehiclePart implements VehicleElement{
5 | private final String type;
6 | private final List parts;
7 |
8 | VehiclePart(String type) {
9 | this.type = type;
10 | this.parts = new ArrayList<>();
11 | }
12 |
13 | @Override
14 | public void addPart(VehiclePart p) {
15 | this.parts.add(p);
16 | }
17 |
18 | @Override
19 | public String toString() {
20 | return "{" +
21 | "type='" + type + '\'' +
22 | ", parts=" + parts +
23 | '}';
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter04/decorator/DecoratorMain.java:
--------------------------------------------------------------------------------
1 | class DecoratorMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Decorator, tuned vehicle");
4 | Vehicle standardVehicle = new StandardVehicle();
5 | Vehicle vehicleToBeTuned = new StandardVehicle();
6 | Vehicle tunedVehicle = new SportVehicle(vehicleToBeTuned, 200);
7 |
8 | System.out.println("Drive a standard vehicle");
9 | standardVehicle.move();
10 |
11 | System.out.println("Drive a tuned vehicle");
12 | tunedVehicle.move();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter04/decorator/SportVehicle.java:
--------------------------------------------------------------------------------
1 | final class SportVehicle extends TunedVehicleDecorator {
2 | private final int horsePower;
3 |
4 | public SportVehicle(Vehicle vehicle, int horsePower) {
5 | super(vehicle);
6 | this.horsePower = horsePower;
7 | }
8 |
9 | @Override
10 | public void move() {
11 | System.out.println("SportVehicle, activate horse power:" + horsePower);
12 | super.move();
13 | }
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter04/decorator/StandardVehicle.java:
--------------------------------------------------------------------------------
1 | public class StandardVehicle implements Vehicle{
2 | @Override
3 | public void move() {
4 | System.out.println("StandardVehicle, move");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter04/decorator/TunedVehicleDecorator.java:
--------------------------------------------------------------------------------
1 | abstract class TunedVehicleDecorator implements Vehicle {
2 | private final Vehicle vehicle;
3 |
4 | TunedVehicleDecorator(Vehicle vehicle) {
5 | this.vehicle = vehicle;
6 | }
7 |
8 |
9 | @Override
10 | public void move() {
11 | System.out.println("TunedVehicleDecorator, turbo on");
12 | vehicle.move();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter04/decorator/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void move();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter04/facade/DieselVehicle.java:
--------------------------------------------------------------------------------
1 | class DieselVehicle implements Vehicle{
2 | @Override
3 | public void start() {
4 | System.out.println("DieselVehicle, engine warm up");
5 | System.out.println("DieselVehicle, engine start");
6 | }
7 |
8 | @Override
9 | public void refuel() {
10 | System.out.println("DieselVehicle, refuel diesel");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter04/facade/FacadeMain.java:
--------------------------------------------------------------------------------
1 | import java.util.Arrays;
2 | import java.util.List;
3 |
4 | class FacadeMain {
5 | public static void main(String[] args) {
6 | System.out.println("Pattern Facade, vehicle types");
7 | List vehicles = Arrays.asList(new DieselVehicle(), new PetrolVehicle());
8 | for (var vehicle: vehicles){
9 | vehicle.start();
10 | vehicle.refuel();
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter04/facade/PetrolVehicle.java:
--------------------------------------------------------------------------------
1 | class PetrolVehicle implements Vehicle{
2 | @Override
3 | public void start() {
4 | System.out.println("PetrolVehicle, engine start");
5 | }
6 |
7 | @Override
8 | public void refuel() {
9 | System.out.println("PetrolVehicle, refuel petrol");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter04/facade/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void start();
3 | void refuel();
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter04/filter/FilterMain.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | class FilterMain {
5 | private static final List vehicleSensors = new ArrayList<>();
6 | static {
7 | vehicleSensors.add(new Sensor("fuel", true));
8 | vehicleSensors.add(new Sensor("fuel", false));
9 | vehicleSensors.add(new Sensor("speed", false));
10 | vehicleSensors.add(new Sensor("speed", true));
11 | }
12 | public static void main(String[] args) {
13 | System.out.println("Pattern Filter, vehicle sensors");
14 | Rule analog = new RuleAnalog();
15 | Rule speedSensor = new RuleType("speed");
16 |
17 | System.out.println("AnalogSensors: " + analog.validateSensors(vehicleSensors));
18 | System.out.println("SpeedSensors: " + speedSensor.validateSensors(vehicleSensors));
19 |
20 | var analogAndSpeedSensors = new RuleAnd(analog, speedSensor);
21 | var analogOrSpeedSensors = new RuleOr(analog, speedSensor);
22 | System.out.println("analogAndSpeedSensors=" + analogAndSpeedSensors.validateSensors(vehicleSensors));
23 | System.out.println("analogOrSpeedSensors=" + analogOrSpeedSensors.validateSensors(vehicleSensors));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter04/filter/Rule.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 |
3 | @FunctionalInterface
4 | interface Rule {
5 | Collection validateSensors(Collection sensors);
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter04/filter/RuleAnalog.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 | import java.util.stream.Collectors;
3 |
4 | class RuleAnalog implements Rule {
5 | @Override
6 | public Collection validateSensors(Collection sensors) {
7 | return sensors.stream()
8 | .filter(Sensor::analog)
9 | .collect(Collectors.toList());
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter04/filter/RuleAnd.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 |
3 | record RuleAnd(Rule rule, Rule additionalRule) implements Rule {
4 | @Override
5 | public Collection validateSensors(Collection sensors) {
6 | Collection initRule = rule.validateSensors(sensors);
7 | return additionalRule.validateSensors(initRule);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter04/filter/RuleOr.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 | import java.util.stream.Collectors;
3 | import java.util.stream.Stream;
4 |
5 | record RuleOr(Rule rule, Rule additionalRule) implements Rule {
6 | @Override
7 | public Collection validateSensors(Collection sensors) {
8 | Collection ruleSensors = rule.validateSensors(sensors);
9 | Collection additionalRuleSensors = additionalRule.validateSensors(sensors);
10 | return Stream.concat(ruleSensors.stream(), additionalRuleSensors.stream())
11 | .distinct().collect(Collectors.toList());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter04/filter/RuleType.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 | import java.util.stream.Collectors;
3 |
4 | class RuleType implements Rule {
5 | private final String type;
6 |
7 | RuleType(String type) {
8 | this.type = type;
9 | }
10 |
11 | @Override
12 | public Collection validateSensors(Collection sensors) {
13 | return sensors.stream()
14 | .filter(s -> s.type().equalsIgnoreCase(type))
15 | .collect(Collectors.toList());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter04/filter/Sensor.java:
--------------------------------------------------------------------------------
1 | record Sensor(String type, boolean analog) {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter04/flyweight/FlyweightMain.java:
--------------------------------------------------------------------------------
1 | class FlyweightMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Flyweight, sharing templates");
4 | Vehicle car1 = VehicleGarage.borrow("sport");
5 | car1.confirm();
6 | Vehicle car2 = VehicleGarage.borrow("sport");
7 | System.out.println("Similar template:" + (car1.equals(car2)));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter04/flyweight/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void confirm();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter04/flyweight/VehicleGarage.java:
--------------------------------------------------------------------------------
1 | import java.util.HashMap;
2 | import java.util.Map;
3 |
4 | class VehicleGarage {
5 |
6 | private static final Map vehicleByType = new HashMap<>();
7 | static {
8 | vehicleByType.put("common", new VehicleType("common-car"));
9 | vehicleByType.put("sport", new VehicleType("sport-car"));
10 | }
11 |
12 | private VehicleGarage() {
13 | }
14 |
15 |
16 | static Vehicle borrow(String type){
17 | Vehicle v = vehicleByType.get(type);
18 | if(v == null){
19 | v = new VehicleType(type);
20 | vehicleByType.put(type, v);
21 | }
22 | // Return only copy, not object
23 | System.out.println("VehicleGarage, borrowed type:" + type);
24 | return v;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Chapter04/flyweight/VehicleType.java:
--------------------------------------------------------------------------------
1 | record VehicleType(String type) implements Vehicle{
2 | @Override
3 | public void confirm() {
4 | System.out.printf("""
5 | Vehicle, type:'%s', confirmed%n""", type);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter04/front_controller/BreaksUnit.java:
--------------------------------------------------------------------------------
1 | class BreaksUnit {
2 | void activate(){
3 | System.out.println("BreaksUnit, activated");
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter04/front_controller/EngineUnit.java:
--------------------------------------------------------------------------------
1 | class EngineUnit {
2 | void start(){
3 | System.out.println("EngineUnit, start");
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter04/front_controller/FrontControllerMain.java:
--------------------------------------------------------------------------------
1 | class FrontControllerMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern FrontController, vehicle system");
4 | var vehicleController = new VehicleController();
5 |
6 | vehicleController.processRequest("engine");
7 | vehicleController.authorize();
8 | vehicleController.processRequest("engine");
9 | vehicleController.processRequest("breaks");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter04/front_controller/RequestDispatcher.java:
--------------------------------------------------------------------------------
1 | record RequestDispatcher(BreaksUnit breaksUnit, EngineUnit engineUnit) {
2 | void dispatch(String command) {
3 | switch (command.toLowerCase()) {
4 | case "engine" -> engineUnit.start();
5 | case "breaks" -> breaksUnit.activate();
6 | default -> throw new IllegalArgumentException("not implemented:" + command);
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter04/front_controller/VehicleController.java:
--------------------------------------------------------------------------------
1 | class VehicleController {
2 | private final RequestDispatcher dispatcher;
3 | private boolean authorized;
4 |
5 | VehicleController() {
6 | this.dispatcher = new RequestDispatcher(new BreaksUnit(), new EngineUnit());
7 | }
8 |
9 | private boolean isAuthorized() {
10 | System.out.println("VehicleController, is authorized");
11 | return authorized;
12 | }
13 |
14 | private void logRequest(String request) {
15 | System.out.printf("""
16 | VehicleController, log:'%s'%n""", request);
17 | }
18 |
19 | void authorize() {
20 | System.out.println("VehicleController, authorization");
21 | authorized = true;
22 | }
23 |
24 | void processRequest(String request) {
25 | logRequest(request);
26 | if (isAuthorized()) {
27 | dispatcher.dispatch(request);
28 | } else {
29 | System.out.printf("""
30 | VehicleController, not authorized request:'%s'%n""", request);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Chapter04/marker/BreaksSensor.java:
--------------------------------------------------------------------------------
1 | record BreaksSensor() implements Sensor {
2 | @Override
3 | public void activate() {
4 | System.out.println("BreaksSensor, activated");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter04/marker/CertifiedAnnotation.java:
--------------------------------------------------------------------------------
1 | import java.lang.annotation.Retention;
2 | import java.lang.annotation.RetentionPolicy;
3 |
4 | @Retention(RetentionPolicy.RUNTIME)
5 | @interface CertifiedAnnotation {
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter04/marker/CertifiedSensor.java:
--------------------------------------------------------------------------------
1 | public interface CertifiedSensor extends Sensor {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter04/marker/ConsumptionSensor.java:
--------------------------------------------------------------------------------
1 | @CertifiedAnnotation
2 | class ConsumptionSensor implements Sensor {
3 | @Override
4 | public void activate() {
5 | System.out.println("ConsumptionSensor, certified, activate");
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter04/marker/EngineSensor.java:
--------------------------------------------------------------------------------
1 | final class EngineSensor implements CertifiedSensor {
2 | @Override
3 | public void activate() {
4 | System.out.println("EngineSensor, certified, active");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter04/marker/MarkerMain.java:
--------------------------------------------------------------------------------
1 | import java.util.Arrays;
2 |
3 | class MarkerMain {
4 | public static void main(String[] args) {
5 | System.out.println("Pattern Marker, sensor identification");
6 | var sensors = Arrays
7 | .asList(new BreaksSensor(), new EngineSensor()
8 | , new ConsumptionSensor());
9 | sensors.forEach(sensor -> {
10 | if(sensor.getClass().isAnnotationPresent(CertifiedAnnotation.class)){
11 | System.out.println("Sensor with Marker annotation:" + sensor);
12 | } else {
13 | switch (sensor){
14 | case CertifiedSensor cs -> System.out.println("Sensor with Marker interface:" + cs);
15 | case Sensor s -> System.out.println("Sensor without identification:"+ s);
16 | }
17 | }
18 | });
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter04/marker/Sensor.java:
--------------------------------------------------------------------------------
1 | public interface Sensor {
2 | void activate();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter04/module/BreaksModule.java:
--------------------------------------------------------------------------------
1 | final class BreaksModule implements VehicleModule{
2 | private static BreaksModule INSTANCE;
3 | static BreaksModule getInstance(){
4 | if(INSTANCE == null){
5 | INSTANCE = new BreaksModule();
6 | }
7 | System.out.println("BreaksModule, unit:" + INSTANCE);
8 | return INSTANCE;
9 | }
10 | private boolean ready;
11 | private BreaksModule(){}
12 |
13 | @Override
14 | public void init() {
15 | System.out.println("BreaksModule, init");
16 | ready = true;
17 | }
18 |
19 |
20 | @Override
21 | public void status() {
22 | System.out.println("BreaksModule, ready:" + ready);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Chapter04/module/EngineModule.java:
--------------------------------------------------------------------------------
1 | final class EngineModule implements VehicleModule {
2 | private static volatile EngineModule INSTANCE;
3 |
4 | static EngineModule getInstance() {
5 | if (INSTANCE == null) {
6 | synchronized (EngineModule.class) {
7 | if (INSTANCE == null) {
8 | INSTANCE = new EngineModule();
9 | }
10 | }
11 | }
12 | System.out.println("EngineModule, unit:" + INSTANCE);
13 | return INSTANCE;
14 | }
15 |
16 | private boolean ready;
17 |
18 | private EngineModule() {
19 | }
20 |
21 | @Override
22 | public void init() {
23 | System.out.println("EngineModule, init");
24 | ready = true;
25 | }
26 |
27 | @Override
28 | public void status() {
29 | System.out.println("EngineModule, ready:" + ready);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Chapter04/module/ModuleMain.java:
--------------------------------------------------------------------------------
1 | class ModuleMain {
2 | private static BreaksModule breaksModule;
3 | private static EngineModule engineModule;
4 |
5 | private static void initModules() {
6 | breaksModule = BreaksModule.getInstance();
7 | engineModule = EngineModule.getInstance();
8 | engineModule.init();
9 | }
10 |
11 | private static void printStatus() {
12 | breaksModule.status();
13 | engineModule.status();
14 | }
15 |
16 | public static void main(String[] args) {
17 | initModules();
18 | printStatus();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Chapter04/module/VehicleModule.java:
--------------------------------------------------------------------------------
1 | sealed interface VehicleModule permits BreaksModule, EngineModule{
2 | void init();
3 | void status();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter04/proxy/ProxyMain.java:
--------------------------------------------------------------------------------
1 | class ProxyMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Proxy, remote vehicle controller");
4 | Vehicle vehicle = new VehicleProxy();
5 | vehicle.move();
6 | vehicle.move();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter04/proxy/Vehicle.java:
--------------------------------------------------------------------------------
1 | interface Vehicle {
2 | void move();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter04/proxy/VehicleProxy.java:
--------------------------------------------------------------------------------
1 | class VehicleProxy implements Vehicle{
2 | private Vehicle vehicleReal;
3 |
4 | @Override
5 | public void move() {
6 | if(vehicleReal == null){
7 | System.out.println("VehicleProxy, real vehicle connected");
8 | vehicleReal = new VehicleReal();
9 | }
10 | vehicleReal.move();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter04/proxy/VehicleReal.java:
--------------------------------------------------------------------------------
1 | class VehicleReal implements Vehicle{
2 | @Override
3 | public void move() {
4 | System.out.println("VehicleReal, move");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter04/twin/AbstractVehiclePart.java:
--------------------------------------------------------------------------------
1 | abstract class AbstractVehiclePart {
2 |
3 | private boolean ready;
4 |
5 | protected AbstractVehiclePart(){
6 | System.out.println("AbstractVehiclePart, constructor");
7 | }
8 |
9 | boolean isReady(){
10 | return ready;
11 | }
12 |
13 | protected void setReady(){
14 | this.ready = true;
15 | }
16 |
17 | abstract void init();
18 | }
19 |
--------------------------------------------------------------------------------
/Chapter04/twin/TwinMain.java:
--------------------------------------------------------------------------------
1 | class TwinMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Twin, vehicle initiation sequence");
4 |
5 | var vehicleBreaks1 = new VehicleBreaks();
6 | var vehicleEngine1 = new VehicleEngine();
7 | vehicleBreaks1.setEngine(vehicleEngine1);
8 | vehicleEngine1.setBreaks(vehicleBreaks1);
9 |
10 | // vehicleBreaks1.init();
11 | vehicleEngine1.init();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter04/twin/VehicleBreaks.java:
--------------------------------------------------------------------------------
1 | public class VehicleBreaks extends AbstractVehiclePart {
2 |
3 | private VehicleEngine twin;
4 |
5 | VehicleBreaks() {
6 | }
7 |
8 | void setEngine(VehicleEngine engine) {
9 | this.twin = engine;
10 | }
11 |
12 | @Override
13 | void init() {
14 | if (twin.isReady()) {
15 | setReady();
16 | } else {
17 | setReady();
18 | twin.init();
19 | }
20 | System.out.println("VehicleBreaks, initiated");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter04/twin/VehicleEngine.java:
--------------------------------------------------------------------------------
1 | final class VehicleEngine extends AbstractVehiclePart {
2 |
3 | private VehicleBreaks twin;
4 |
5 | VehicleEngine() {
6 | }
7 |
8 | void setBreaks(VehicleBreaks breaks) {
9 | this.twin = breaks;
10 | }
11 |
12 | @Override
13 | void init() {
14 | if (twin.isReady()) {
15 | setReady();
16 | } else {
17 | setReady();
18 | twin.init();
19 | }
20 | System.out.println("VehicleEngine, initiated");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter05/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
2 | ## Chapter 5 - behavioral pattern examples
3 | ```bash
4 | # Caching
5 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/caching -sourcepath java -d out/Chapter05/caching ./Chapter05/caching/*.java
6 | $ java --enable-preview -cp out/Chapter05/caching CachingMain
7 |
8 | # Chain of responsibility
9 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/chain_responsibility -sourcepath java -d out/Chapter05/chain_responsibility ./Chapter05/chain_responsibility/*.java
10 | $ java --enable-preview -cp out/Chapter05/chain_responsibility ChainOfResponsibilityMain
11 |
12 | # Command
13 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/command -sourcepath java -d out/Chapter05/command ./Chapter05/command/*.java
14 | $ java --enable-preview -cp out/Chapter05/command CommandMain
15 |
16 | # Interpreter
17 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/interpreter -sourcepath java -d out/Chapter05/interpreter ./Chapter05/interpreter/*.java
18 | $ java --enable-preview -cp out/Chapter05/interpreter InterpreterMain
19 |
20 | # Iterator
21 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/iterator -sourcepath java -d out/Chapter05/iterator ./Chapter05/iterator/*.java
22 | $ java --enable-preview -cp out/Chapter05/iterator IteratorMain
23 |
24 | # Mediator
25 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/mediator -sourcepath java -d out/Chapter05/mediator ./Chapter05/mediator/*.java
26 | $ java --enable-preview -cp out/Chapter05/mediator MediatorMain
27 |
28 | # Null object
29 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/null_object -sourcepath java -d out/Chapter05/null_object ./Chapter05/null_object/*.java
30 | $ java --enable-preview -cp out/Chapter05/null_object NullObjectMain
31 |
32 | # Observer
33 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/observer -sourcepath java -d out/Chapter05/observer ./Chapter05/observer/*.java
34 | $ java --enable-preview -cp out/Chapter05/observer ObserverMain
35 |
36 | # Pipeline
37 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/pipeline -sourcepath java -d out/Chapter05/pipeline ./Chapter05/pipeline/*.java
38 | $ java --enable-preview -cp out/Chapter05/pipeline PipelineMain
39 |
40 | # State
41 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/state -sourcepath java -d out/Chapter05/state ./Chapter05/state/*.java
42 | $ java --enable-preview -cp out/Chapter05/state StateMain
43 |
44 | # Strategy
45 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/strategy -sourcepath java -d out/Chapter05/strategy ./Chapter05/strategy/*.java
46 | $ java --enable-preview -cp out/Chapter05/strategy StrategyMain
47 |
48 | # Template method
49 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/template_method -sourcepath java -d out/Chapter05/template_method ./Chapter05/template_method/*.java
50 | $ java --enable-preview -cp out/Chapter05/template_method TemplateMethodMain
51 |
52 | # Visitor
53 | $ javac --release 17 --enable-preview -g -cp out/Chapter05/visitor -sourcepath java -d out/Chapter05/visitor ./Chapter05/visitor/*.java
54 | $ java --enable-preview -cp out/Chapter05/visitor VisitorMain
55 | ```
56 |
--------------------------------------------------------------------------------
/Chapter05/caching/BreakSystem.java:
--------------------------------------------------------------------------------
1 | import java.util.Objects;
2 |
3 | final class BreakSystem implements VehicleSystem {
4 | private final String name;
5 | private boolean active;
6 |
7 | BreakSystem(String name) {
8 | this.name = name;
9 | }
10 |
11 | @Override
12 | public String type() {
13 | return name;
14 | }
15 |
16 | @Override
17 | public void init() {
18 |
19 | }
20 |
21 | @Override
22 | public boolean active() {
23 | return false;
24 | }
25 |
26 | @Override
27 | public boolean equals(Object o) {
28 | if (this == o) return true;
29 | if (o == null || getClass() != o.getClass()) return false;
30 | BreakSystem that = (BreakSystem) o;
31 | return active == that.active && Objects.equals(name, that.name);
32 | }
33 |
34 | @Override
35 | public int hashCode() {
36 | return Objects.hash(name, active);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Chapter05/caching/CachingMain.java:
--------------------------------------------------------------------------------
1 | class CachingMain {
2 | public static void main(String[] args) {
3 | System.out.println("Caching Pattern, initiated vehicle system");
4 | var vehicle = new Vehicle();
5 | vehicle.init();
6 | var suspension = new SuspensionSystem("suspension");
7 | vehicle.addSystem(suspension);
8 | System.out.printf("Systems types:'%s%n", vehicle.systemTypes());
9 |
10 | var suspensionCache = vehicle.getSystemByType("suspension");
11 | System.out.printf("Is suspension equal? '%s:%s'%n", suspension.equals(suspensionCache), suspensionCache);
12 | vehicle.addSystem(new EngineSystem("engine2"));
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter05/caching/EngineSystem.java:
--------------------------------------------------------------------------------
1 | import java.util.Objects;
2 |
3 | final class EngineSystem implements VehicleSystem {
4 |
5 | private final String type;
6 | private boolean active;
7 |
8 | EngineSystem(String type) {
9 | this.type = type;
10 | }
11 |
12 | @Override
13 | public String type() {
14 | return type;
15 | }
16 |
17 | @Override
18 | public void init() {
19 | this.active = true;
20 | }
21 |
22 | @Override
23 | public boolean active() {
24 | return active;
25 | }
26 |
27 | @Override
28 | public boolean equals(Object o) {
29 | if (this == o) return true;
30 | if (o == null || getClass() != o.getClass()) return false;
31 | EngineSystem that = (EngineSystem) o;
32 | return active == that.active && Objects.equals(type, that.type);
33 | }
34 |
35 | @Override
36 | public int hashCode() {
37 | return Objects.hash(type, active);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Chapter05/caching/SuspensionSystem.java:
--------------------------------------------------------------------------------
1 | import java.util.Objects;
2 |
3 | final class SuspensionSystem implements VehicleSystem {
4 | private final String type;
5 | private boolean active;
6 |
7 | public SuspensionSystem(String type) {
8 | this.type = type;
9 | }
10 |
11 | @Override
12 | public String type() {
13 | return type;
14 | }
15 |
16 | @Override
17 | public void init() {
18 | this.active = true;
19 | }
20 |
21 | @Override
22 | public boolean active() {
23 | return active;
24 | }
25 |
26 | @Override
27 | public boolean equals(Object o) {
28 | if (this == o) return true;
29 | if (o == null || getClass() != o.getClass()) return false;
30 | SuspensionSystem that = (SuspensionSystem) o;
31 | return active == that.active && Objects.equals(type, that.type);
32 | }
33 |
34 | @Override
35 | public int hashCode() {
36 | return Objects.hash(type, active);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Chapter05/caching/SystemCache.java:
--------------------------------------------------------------------------------
1 | import java.util.Objects;
2 | import java.util.stream.Collectors;
3 | import java.util.stream.Stream;
4 |
5 | class SystemCache {
6 | private final VehicleSystem[] systems;
7 | private int end;
8 |
9 | SystemCache(int capacity) {
10 | this.systems = new VehicleSystem[capacity];
11 | }
12 |
13 | boolean addSystem(VehicleSystem system) {
14 | var availableSystem = getSystem(system.type());
15 | if (availableSystem == null && end < systems.length) {
16 | systems[end++] = system;
17 | return true;
18 | }
19 | return false;
20 | }
21 |
22 | VehicleSystem getSystem(String type) {
23 | for (VehicleSystem s : systems) {
24 | if (s != null && s.type().equals(type)) {
25 | return s;
26 | }
27 | }
28 | return null;
29 | }
30 |
31 | int currentSize(){
32 | return end;
33 | }
34 |
35 | String getSystemTypes() {
36 | return Stream.of(systems).filter(Objects::nonNull).map(s -> """
37 | '%s':'%s'""".formatted(s.type(), s)).collect(Collectors.joining(","));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Chapter05/caching/Vehicle.java:
--------------------------------------------------------------------------------
1 | class Vehicle {
2 | private final SystemCache cache = new SystemCache(3);
3 |
4 | void init(){
5 | cache.addSystem(new BreakSystem("break"));
6 | cache.addSystem(new EngineSystem("engine"));
7 | System.out.println("Vehicle, init cache:" + systemTypes());
8 | }
9 |
10 | void addSystem(VehicleSystem s){
11 | if(!cache.addSystem(s)){
12 | System.err.println("SystemCache, not stored:" + s);
13 | }
14 | }
15 |
16 | String systemTypes(){
17 | return cache.getSystemTypes();
18 | }
19 |
20 | VehicleSystem getSystemByType(String type){
21 | return cache.getSystem(type);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/Chapter05/caching/VehicleSystem.java:
--------------------------------------------------------------------------------
1 | sealed interface VehicleSystem permits BreakSystem, EngineSystem, SuspensionSystem {
2 | String type();
3 | void init();
4 | boolean active();
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter05/chain_responsibility/ChainOfResponsibilityMain.java:
--------------------------------------------------------------------------------
1 | class ChainOfResponsibilityMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Chain of Responsibility, vehicle system initialisation");
4 | var engineSystem = new EngineSystem();
5 | var driverSystem = new DriverSystem();
6 | var transmissionSystem = new TransmissionSystem();
7 |
8 | driverSystem.setNext(transmissionSystem);
9 | transmissionSystem.setNext(engineSystem);
10 |
11 | driverSystem.powerOn();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter05/chain_responsibility/DriverSystem.java:
--------------------------------------------------------------------------------
1 | final class DriverSystem extends VehicleSystem {
2 |
3 | DriverSystem() {
4 | super(SystemType.DRIVER);
5 | }
6 |
7 | @Override
8 | void activate() {
9 | System.out.println("DriverSystem: activated");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/chain_responsibility/EngineSystem.java:
--------------------------------------------------------------------------------
1 | final class EngineSystem extends VehicleSystem {
2 |
3 | EngineSystem() {
4 | super(SystemType.ENGINE);
5 | }
6 |
7 | @Override
8 | void activate() {
9 | System.out.println("EngineSystem, activated");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/chain_responsibility/SystemType.java:
--------------------------------------------------------------------------------
1 | enum SystemType {
2 | DRIVER(2),
3 | TRANSMISSION(1),
4 | ENGINE(0),
5 | UNKNOWN(-1);
6 |
7 | private final int order;
8 |
9 | SystemType(int order) {
10 | this.order = order;
11 | }
12 |
13 | int order() {
14 | return order;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter05/chain_responsibility/TransmissionSystem.java:
--------------------------------------------------------------------------------
1 | final class TransmissionSystem extends VehicleSystem{
2 |
3 | TransmissionSystem() {
4 | super(SystemType.TRANSMISSION);
5 | }
6 |
7 | @Override
8 | void activate() {
9 | System.out.println("TransmissionSystem: activated");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/chain_responsibility/VehicleSystem.java:
--------------------------------------------------------------------------------
1 | sealed abstract class VehicleSystem permits DriverSystem, EngineSystem, TransmissionSystem {
2 |
3 | protected final SystemType type;
4 | protected VehicleSystem nextSystem;
5 | protected boolean active;
6 |
7 | VehicleSystem(SystemType type) {
8 | this.type = type;
9 | }
10 |
11 | void setNext(VehicleSystem system){
12 | this.nextSystem = system;
13 | }
14 |
15 | void powerOn(){
16 | if(!this.active){
17 | activate();
18 | }
19 | if(nextSystem != null){
20 | nextSystem.powerOn();
21 | }
22 | }
23 |
24 | abstract void activate();
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter05/command/CommandMain.java:
--------------------------------------------------------------------------------
1 | class CommandMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pattern Command, turn on/off vehicle");
4 |
5 | var vehicle = new Vehicle("sport-car");
6 | var driver = new Driver();
7 | driver.addCommand(new StartCommand(vehicle));
8 | driver.addCommand(new StopCommand(vehicle));
9 | driver.addCommand(new StartCommand(vehicle));
10 |
11 | driver.executeCommands("start_stop");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter05/command/Driver.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | class Driver {
5 | private final List commands = new ArrayList<>();
6 |
7 | void addCommand(VehicleCommand command){
8 | commands.add(command);
9 | }
10 |
11 | void executeCommands(final String command){
12 | commands.forEach(c -> c.process(command));
13 | commands.clear();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter05/command/StartCommand.java:
--------------------------------------------------------------------------------
1 | record StartCommand(Vehicle vehicle) implements VehicleCommand {
2 | @Override
3 | public void process(String command) {
4 | if(command.contains("start")){
5 | vehicle.start();
6 | System.out.println("START:" + vehicle);
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter05/command/StopCommand.java:
--------------------------------------------------------------------------------
1 | record StopCommand(Vehicle vehicle) implements VehicleCommand{
2 | @Override
3 | public void process(String command) {
4 | if(command.contains("stop")){
5 | vehicle.stop();
6 | System.out.println("STOP:" + vehicle);
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter05/command/Vehicle.java:
--------------------------------------------------------------------------------
1 | final class Vehicle {
2 | private final String type;
3 | private boolean running;
4 |
5 | Vehicle(String type) {
6 | this.type = type;
7 | }
8 |
9 | void start() {
10 | this.running = true;
11 | }
12 |
13 | void stop() {
14 | this.running = false;
15 | }
16 |
17 | boolean isRunning() {
18 | return running;
19 | }
20 |
21 | @Override
22 | public String toString() {
23 | return "Vehicle{" +
24 | "type='" + type + '\'' +
25 | ", running=" + running +
26 | '}';
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Chapter05/command/VehicleCommand.java:
--------------------------------------------------------------------------------
1 | sealed interface VehicleCommand permits StartCommand, StopCommand {
2 | void process(String command);
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter05/interpreter/Expression.java:
--------------------------------------------------------------------------------
1 | interface Expression {
2 | int interpret();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter05/interpreter/IntegerExpression.java:
--------------------------------------------------------------------------------
1 | class IntegerExpression implements Expression{
2 | private final int value;
3 |
4 | IntegerExpression(String value) {
5 | this.value = Integer.parseInt(value);
6 | }
7 |
8 | @Override
9 | public int interpret() {
10 | return value;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter05/interpreter/InterpreterMain.java:
--------------------------------------------------------------------------------
1 | import java.util.Stack;
2 |
3 | class InterpreterMain {
4 | public static void main(String[] args) {
5 | System.out.println("Pattern Interpreter, math formula evaluation");
6 | var stack = new Stack();
7 | var formula = "1 - 3 + 100 + 1";
8 | var parsedFormula = formula.split(" ");
9 |
10 | var index = 0;
11 | while (index < parsedFormula.length ){
12 | var text = parsedFormula[index++];
13 | if(isOperator(text)){
14 | var leftExp = stack.pop();
15 | var rightText = parsedFormula[index++];
16 | var rightExp = new IntegerExpression(rightText);
17 | var operatorExp = getEvaluationExpression(text, leftExp, rightExp);
18 | stack.push(operatorExp);
19 | } else {
20 | var exp = new IntegerExpression(text);
21 | stack.push(exp);
22 | }
23 | }
24 | System.out.println("Formula result: " + stack.pop().interpret());
25 | }
26 |
27 | private static boolean isOperator(String text){
28 | return text.equals("+") || text.equals("-");
29 | }
30 |
31 | private static Expression getEvaluationExpression(String operator, Expression left, Expression right){
32 | return switch (operator){
33 | case "+" -> new PlusExpression(left, right);
34 | case "-" -> new MinusExpression(left, right);
35 | default -> throw new IllegalArgumentException("not implemented");
36 | };
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Chapter05/interpreter/MinusExpression.java:
--------------------------------------------------------------------------------
1 | class MinusExpression implements Expression {
2 | private final Expression e1;
3 | private final Expression e2;
4 |
5 | MinusExpression(Expression e1, Expression e2) {
6 | this.e1 = e1;
7 | this.e2 = e2;
8 | }
9 |
10 | @Override
11 | public int interpret() {
12 | return e1.interpret() - e2.interpret();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter05/interpreter/PlusExpression.java:
--------------------------------------------------------------------------------
1 | class PlusExpression implements Expression {
2 |
3 | private final Expression temp1;
4 | private final Expression temp2;
5 |
6 | PlusExpression(Expression temp1, Expression temp2) {
7 | this.temp1 = temp1;
8 | this.temp2 = temp2;
9 | }
10 |
11 | @Override
12 | public int interpret() {
13 | return temp1.interpret() + temp2.interpret();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter05/iterator/IteratorMain.java:
--------------------------------------------------------------------------------
1 | class IteratorMain {
2 | public static void main(String[] args) {
3 | System.out.println("Iterator Pattern, vehicle parts");
4 | var standardVehicle = new StandardVehicle();
5 | for(PartsIterator part = standardVehicle.getParts(); part.hasNext();){
6 | var vehiclePart = part.next();
7 | System.out.println("VehiclePart name:" + vehiclePart.name());
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter05/iterator/PartsIterator.java:
--------------------------------------------------------------------------------
1 | interface PartsIterator {
2 | boolean hasNext();
3 | VehiclePart next();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter05/iterator/StandardVehicle.java:
--------------------------------------------------------------------------------
1 | final class StandardVehicle implements Vehicle {
2 |
3 | private final String[] vehiclePartsNames = {"engine", "breaks", "navigation"};
4 | private class VehiclePartsIterator implements PartsIterator {
5 |
6 | private int currentIndex;
7 |
8 | @Override
9 | public boolean hasNext() {
10 | return currentIndex < vehiclePartsNames.length;
11 | }
12 |
13 | @Override
14 | public VehiclePart next() {
15 | return hasNext() ? new VehiclePart(vehiclePartsNames[currentIndex++]) : null;
16 | }
17 | }
18 |
19 | @Override
20 | public PartsIterator getParts() {
21 | return new VehiclePartsIterator();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Chapter05/iterator/Vehicle.java:
--------------------------------------------------------------------------------
1 | sealed interface Vehicle permits StandardVehicle {
2 | PartsIterator getParts();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter05/iterator/VehiclePart.java:
--------------------------------------------------------------------------------
1 | record VehiclePart(String name) {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter05/mediator/MediatorMain.java:
--------------------------------------------------------------------------------
1 | class MediatorMain {
2 | public static void main(String[] args) {
3 | System.out.println("Mediator Pattern, vehicle parts");
4 | var engineSensor = new Sensor("engine");
5 | var breakSensor = new Sensor("break");
6 |
7 | engineSensor.emitMessage("turn on");
8 | breakSensor.emitMessage("init");
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/mediator/Sensor.java:
--------------------------------------------------------------------------------
1 | record Sensor(String name) {
2 | void emitMessage(String message) {
3 | VehicleProcessor.acceptMessage(name, message);
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter05/mediator/VehicleProcessor.java:
--------------------------------------------------------------------------------
1 | final class VehicleProcessor {
2 | static void acceptMessage(String sensorType, String message){
3 | System.out.printf("""
4 | Sensor:'%s', delivered message:'%s'%n""", sensorType, message);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/memento/AirConditionSystemCareTaker.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | final class AirConditionSystemCareTaker {
5 | private final List memory = new ArrayList<>();
6 |
7 | AirConditionSystemCareTaker() {
8 | }
9 |
10 | int add(SystemMemento m) {
11 | int pos = memory.size();
12 | memory.add(m);
13 | return pos;
14 | }
15 |
16 | SystemMemento getMemento(int i) {
17 | return memory.get(i);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter05/memento/AirConditionSystemOriginator.java:
--------------------------------------------------------------------------------
1 | final class AirConditionSystemOriginator {
2 | private String state;
3 |
4 | void setState(String s){
5 | this.state = s;
6 | }
7 |
8 | String getState(){
9 | return state;
10 | }
11 |
12 | int saveState(AirConditionSystemCareTaker careTaker){
13 | return careTaker.add(new SystemMemento(state));
14 | }
15 |
16 | void restoreState(SystemMemento m){
17 | state = m.state();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter05/memento/MementoMain.java:
--------------------------------------------------------------------------------
1 | class MementoMain {
2 | public static void main(String[] args) {
3 | System.out.println("Memento Pattern, air-condition system");
4 | var originator = new AirConditionSystemOriginator();
5 | var careTaker = new AirConditionSystemCareTaker();
6 |
7 | originator.setState("low");
8 | var stateLow = originator.saveState(careTaker);
9 | originator.setState("medium");
10 | var stateMedium = originator.saveState(careTaker);
11 | originator.setState("high");
12 | var stateHigh = originator.saveState(careTaker);
13 |
14 | System.out.printf("""
15 | Current Air-Condition System state:'%s'%n""", originator.getState());
16 |
17 | originator.restoreState(careTaker.getMemento(stateLow));
18 | System.out.printf("""
19 | Restored position:'%d', Air-Condition System state:'%s'%n""", stateLow, originator.getState());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Chapter05/memento/SystemMemento.java:
--------------------------------------------------------------------------------
1 | record SystemMemento(String state) {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter05/null_object/AbstractSensor.java:
--------------------------------------------------------------------------------
1 | sealed abstract class AbstractSensor permits NullSensor, VehicleSensor {
2 | protected final String type;
3 |
4 | AbstractSensor(String type) {
5 | this.type = type;
6 | }
7 |
8 | abstract boolean isAvailable();
9 | String getType(){
10 | return type;
11 | }
12 |
13 | @Override
14 | public String toString() {
15 | return "Sensor{" +
16 | "type='" + type + '\'' +
17 | '}';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter05/null_object/NullObjectMain.java:
--------------------------------------------------------------------------------
1 | class NullObjectMain {
2 | public static void main(String[] args) {
3 | System.out.println("Null Object Pattern, vehicle sensor");
4 |
5 | var engineSensor = VehicleSensorsProvider.getSenorByType("engine");
6 | var transmissionSensor = VehicleSensorsProvider.getSenorByType("transmission");
7 | System.out.println("Engine Sensor: " + engineSensor);
8 | System.out.println("Transmission Sensor: " + transmissionSensor);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter05/null_object/NullSensor.java:
--------------------------------------------------------------------------------
1 | final class NullSensor extends AbstractSensor{
2 |
3 | public NullSensor() {
4 | super("not_available");
5 | }
6 |
7 | @Override
8 | boolean isAvailable() {
9 | return false;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/null_object/VehicleSensor.java:
--------------------------------------------------------------------------------
1 | final class VehicleSensor extends AbstractSensor{
2 |
3 | VehicleSensor(String type) {
4 | super(type);
5 | }
6 |
7 | @Override
8 | boolean isAvailable() {
9 | return true;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/null_object/VehicleSensorsProvider.java:
--------------------------------------------------------------------------------
1 | import java.util.List;
2 | import java.util.stream.Stream;
3 |
4 | final class VehicleSensorsProvider {
5 | private static final List sensors = Stream.of("engine", "breaks")
6 | .map(String::toLowerCase).map(VehicleSensor::new)
7 | .map(AbstractSensor.class::cast).toList();
8 |
9 | private VehicleSensorsProvider(){}
10 |
11 | static AbstractSensor getSenorByType(String type){
12 | return sensors.stream().filter(s -> s.type.equals(type))
13 | .findFirst()
14 | .orElseGet(NullSensor::new);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter05/observer/CockpitObserver.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 |
3 | final class CockpitObserver extends SystemObserver {
4 | private static final Random RANDOM = new Random();
5 | public CockpitObserver(VehicleSystem system) {
6 | super(system);
7 | this.system.attach(this);
8 | }
9 |
10 | @Override
11 | void update() {
12 | System.out.printf("""
13 | CockpitObserver, temperature:'%d'%n""", getTemperature());
14 | }
15 |
16 | private int getTemperature(){
17 | return RANDOM.nextInt(0, 30);
18 | }
19 | }
--------------------------------------------------------------------------------
/Chapter05/observer/EngineObserver.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 |
3 | final class EngineObserver extends SystemObserver {
4 | private static final Random RANDOM = new Random();
5 | public EngineObserver(VehicleSystem system) {
6 | super(system);
7 | this.system.attach(this);
8 | }
9 |
10 | @Override
11 | void update() {
12 | System.out.printf("""
13 | EngineObserver, temperature:'%d'%n""", getTemperature());
14 | }
15 |
16 | private int getTemperature(){
17 | return RANDOM.nextInt(0, 100);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter05/observer/ObserverMain.java:
--------------------------------------------------------------------------------
1 | class ObserverMain {
2 | public static void main(String[] args) {
3 | System.out.println("Observer Pattern, vehicle temperature senors");
4 | var temperatureControlSystem = new VehicleSystem();
5 | new CockpitObserver(temperatureControlSystem);
6 | new EngineObserver(temperatureControlSystem);
7 |
8 | temperatureControlSystem.setState("low");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter05/observer/SystemObserver.java:
--------------------------------------------------------------------------------
1 | sealed abstract class SystemObserver permits CockpitObserver, EngineObserver {
2 | protected final VehicleSystem system;
3 |
4 | SystemObserver(VehicleSystem system) {
5 | this.system = system;
6 | }
7 |
8 | abstract void update();
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter05/observer/VehicleSystem.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | class VehicleSystem {
5 | private final List observers = new ArrayList<>();
6 | private String state;
7 |
8 | String state() {
9 | return state;
10 | }
11 |
12 | void setState(String s) {
13 | this.state = s;
14 | observersNotifyAll();
15 | }
16 |
17 | void attach(SystemObserver systemObserver){
18 | observers.add(systemObserver);
19 | }
20 |
21 | private void observersNotifyAll(){
22 | observers.forEach(SystemObserver::update);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/BreakProcessor.java:
--------------------------------------------------------------------------------
1 | class BreakProcessor implements Processor{
2 | @Override
3 | public SystemElement process(SystemElement input) {
4 | input.addLog("break-system");
5 | return input;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/Element.java:
--------------------------------------------------------------------------------
1 | sealed interface Element permits SystemElement {
2 | void addLog(String log);
3 | String logSummary();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/EngineProcessor.java:
--------------------------------------------------------------------------------
1 | class EngineProcessor implements Processor{
2 |
3 |
4 | @Override
5 | public SystemElement process(SystemElement input) {
6 | input.addLog("engine-system");
7 | return input;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/PipeElement.java:
--------------------------------------------------------------------------------
1 | class PipeElement {
2 | private final Processor processor;
3 |
4 | PipeElement(Processor processor) {
5 | this.processor = processor;
6 | }
7 |
8 | PipeElement addProcessor(Processor p){
9 | return new PipeElement<>(input -> p.process(processor.process(input)));
10 | }
11 |
12 | R process(E inputElement){
13 | return processor.process(inputElement);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/PipelineMain.java:
--------------------------------------------------------------------------------
1 | class PipelineMain {
2 | public static void main(String[] args) {
3 | System.out.println("Pipeline Pattern, vehicle turn on states");
4 | var pipeline = new PipeElement<>(new EngineProcessor())
5 | .addProcessor(new BreakProcessor())
6 | .addProcessor(new TransmissionProcessor());
7 |
8 | var systemState = pipeline.process(new SystemElement());
9 | System.out.println(systemState.logSummary());
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/Processor.java:
--------------------------------------------------------------------------------
1 | @FunctionalInterface
2 | interface Processor {
3 | R process (E input);
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/SystemElement.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | final class SystemElement implements Element{
5 | private final List log = new ArrayList<>();
6 |
7 | @Override
8 | public void addLog(String log) {
9 | this.log.add(log);
10 | }
11 |
12 | @Override
13 | public String logSummary() {
14 | return String.join(",", log);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter05/pipeline/TransmissionProcessor.java:
--------------------------------------------------------------------------------
1 | class TransmissionProcessor implements Processor{
2 |
3 | @Override
4 | public SystemElement process(SystemElement input) {
5 | input.addLog("transmission-system");
6 | return input;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter05/state/InitState.java:
--------------------------------------------------------------------------------
1 | class InitState implements VehicleState{
2 | private Vehicle vehicle;
3 |
4 | @Override
5 | public void onAction() {
6 | System.out.printf("Turning on the key, vehicle:'%s'%n",vehicle);
7 | }
8 |
9 | @Override
10 | public void evaluate() {
11 | System.out.printf("Initiation sequence, vehicle:'%s'%n",vehicle);
12 | }
13 |
14 | @Override
15 | public void setVehicle(Vehicle vehicle) {
16 | this.vehicle = vehicle;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return "InitState{" +
22 | "vehicle=" + vehicle.getModel() +
23 | '}';
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter05/state/StartState.java:
--------------------------------------------------------------------------------
1 | class StartState implements VehicleState{
2 | private Vehicle vehicle;
3 |
4 | @Override
5 | public void onAction() {
6 | System.out.printf("Engine is warming up, vehicle:'%s'%n",vehicle);
7 | }
8 |
9 | @Override
10 | public void evaluate() {
11 | System.out.printf("Engine is running, vehicle:'%s'%n",vehicle);
12 | }
13 |
14 | @Override
15 | public void setVehicle(Vehicle vehicle) {
16 | this.vehicle = vehicle;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return "StartState{" +
22 | "vehicle=" + vehicle.getModel() +
23 | '}';
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter05/state/StateMain.java:
--------------------------------------------------------------------------------
1 | class StateMain {
2 | public static void main(String[] args) {
3 | System.out.println("State Pattern, vehicle turn on states");
4 | var vehicle = new Vehicle("truck");
5 | System.out.println("Vehicle state1:" + vehicle.getState());
6 |
7 | var initState = new InitState();
8 | var startState = new StartState();
9 | var stopState = new StopState();
10 |
11 | vehicle.setState(initState);
12 | System.out.println("Vehicle state2:" + vehicle.getState());
13 | vehicle.setState(startState);
14 | System.out.println("Vehicle state3:" + vehicle.getState());
15 | vehicle.setState(stopState);
16 | System.out.println("Vehicle state4:" + vehicle.getState());
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter05/state/StopState.java:
--------------------------------------------------------------------------------
1 | final class StopState implements VehicleState{
2 | private Vehicle vehicle;
3 |
4 | @Override
5 | public void onAction() {
6 | System.out.printf("Engine is turning off, vehicle:'%s'%n",vehicle);
7 | }
8 |
9 | @Override
10 | public void evaluate() {
11 | System.out.printf("Engine is down, vehicle:'%s'%n",vehicle);
12 | }
13 |
14 | @Override
15 | public void setVehicle(Vehicle vehicle) {
16 | this.vehicle = vehicle;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return "StopState{" +
22 | "vehicle=" + vehicle.getModel() +
23 | '}';
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter05/state/Vehicle.java:
--------------------------------------------------------------------------------
1 | final class Vehicle {
2 | private final String model;
3 | private VehicleState state;
4 |
5 | Vehicle(String model) {
6 | this.model = model;
7 | }
8 |
9 | String getModel() {
10 | return model;
11 | }
12 |
13 | VehicleState getState() {
14 | return state;
15 | }
16 |
17 | void setState(VehicleState state) {
18 | state.setVehicle(this);
19 | this.state = state;
20 |
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return "Vehicle{" +
26 | "model='" + model + '}';
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Chapter05/state/VehicleState.java:
--------------------------------------------------------------------------------
1 | interface VehicleState {
2 | void onAction();
3 | void evaluate();
4 |
5 | void setVehicle(Vehicle vehicle);
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/strategy/BusStrategy.java:
--------------------------------------------------------------------------------
1 | final class BusStrategy implements TransportStrategy{
2 | @Override
3 | public void transport() {
4 | System.out.println("Bus, whole crew transport");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/strategy/CarStrategy.java:
--------------------------------------------------------------------------------
1 | final class CarStrategy implements TransportStrategy{
2 | @Override
3 | public void transport() {
4 | System.out.println("Car, four persons transport");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/strategy/StrategyMain.java:
--------------------------------------------------------------------------------
1 | class StrategyMain {
2 | public static void main(String[] args) {
3 | System.out.println("Strategy Pattern, changing transport options");
4 |
5 | var driver = new VehicleDriver(new CarStrategy());
6 | driver.transport();
7 | driver.changeStrategy(new BusStrategy());
8 | driver.transport();
9 | driver.changeStrategy(new TruckStrategy());
10 | driver.transport();
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter05/strategy/TransportStrategy.java:
--------------------------------------------------------------------------------
1 | @FunctionalInterface
2 | interface TransportStrategy {
3 | void transport();
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter05/strategy/TruckStrategy.java:
--------------------------------------------------------------------------------
1 | final class TruckStrategy implements TransportStrategy{
2 | @Override
3 | public void transport() {
4 | System.out.println("Truck, transporting heavy load");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/strategy/VehicleDriver.java:
--------------------------------------------------------------------------------
1 | class VehicleDriver {
2 | private TransportStrategy strategy;
3 |
4 | VehicleDriver(TransportStrategy strategy) {
5 | this.strategy = strategy;
6 | }
7 |
8 | void changeStrategy(TransportStrategy strategy){
9 | this.strategy = strategy;
10 | }
11 |
12 |
13 | void transport(){
14 | strategy.transport();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter05/template_method/BreaksSensor.java:
--------------------------------------------------------------------------------
1 | final class BreaksSensor extends VehicleSensor{
2 | @Override
3 | void init() {
4 | System.out.println("BreaksSensor, initiated");
5 | }
6 |
7 | @Override
8 | void startMeasure() {
9 | System.out.println("BreaksSensor, measurement started");
10 | }
11 |
12 | @Override
13 | void storeData() {
14 | System.out.println("BreaksSensor, data stored");
15 | }
16 |
17 | @Override
18 | void stopMeasure() {
19 | System.out.println("BreaksSensor, measurement stopped");
20 | }
21 | }
--------------------------------------------------------------------------------
/Chapter05/template_method/EngineSensor.java:
--------------------------------------------------------------------------------
1 | final class EngineSensor extends VehicleSensor{
2 | @Override
3 | void init() {
4 | System.out.println("EngineSensor, initiated");
5 | }
6 |
7 | @Override
8 | protected void startMeasure() {
9 | System.out.println("EngineSensor, measurement started");
10 | }
11 |
12 | @Override
13 | void storeData() {
14 | System.out.println("EngineSensor, data stored");
15 | }
16 |
17 | @Override
18 | void stopMeasure() {
19 | System.out.println("EngineSensor, measurement stopped");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Chapter05/template_method/TemplateMethodMain.java:
--------------------------------------------------------------------------------
1 | import java.util.Arrays;
2 |
3 | class TemplateMethodMain {
4 | public static void main(String[] args) {
5 | System.out.println("Template method Pattern, changing transport options");
6 | Arrays.asList(new BreaksSensor(), new EngineSensor())
7 | .forEach(VehicleSensor::activate);
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter05/template_method/VehicleSensor.java:
--------------------------------------------------------------------------------
1 | abstract sealed class VehicleSensor permits BreaksSensor, EngineSensor {
2 | abstract void init();
3 | abstract void startMeasure();
4 | abstract void storeData();
5 | abstract void stopMeasure();
6 |
7 | final void activate(){
8 | init();
9 | startMeasure();
10 | storeData();
11 | stopMeasure();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter05/visitor/BreaksCheck.java:
--------------------------------------------------------------------------------
1 | public class BreaksCheck implements SystemCheck {
2 | @Override
3 | public void accept(CheckVisitor visitor) {
4 | visitor.visit(this);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/visitor/CheckVisitor.java:
--------------------------------------------------------------------------------
1 | interface CheckVisitor {
2 | void visit(EngineCheck engineCheck);
3 |
4 | void visit(SuspensionCheck suspensionCheck);
5 |
6 | void visit(BreaksCheck breaksCheck);
7 |
8 | void visit(VehicleCheck vehicleCheck);
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter05/visitor/EngineCheck.java:
--------------------------------------------------------------------------------
1 | class EngineCheck implements SystemCheck {
2 | @Override
3 | public void accept(CheckVisitor visitor) {
4 | visitor.visit(this);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/visitor/SuspensionCheck.java:
--------------------------------------------------------------------------------
1 | class SuspensionCheck implements SystemCheck {
2 | @Override
3 | public void accept(CheckVisitor visitor) {
4 | visitor.visit(this);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter05/visitor/SystemCheck.java:
--------------------------------------------------------------------------------
1 | interface SystemCheck {
2 | void accept(CheckVisitor visitor);
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter05/visitor/VehicleCheck.java:
--------------------------------------------------------------------------------
1 | class VehicleCheck implements SystemCheck {
2 | private final SystemCheck[] systems = {new BreaksCheck(), new EngineCheck(), new SuspensionCheck()};
3 |
4 | @Override
5 | public void accept(CheckVisitor visitor) {
6 | for (SystemCheck check : systems) {
7 | check.accept(visitor);
8 | }
9 | visitor.visit(this);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/visitor/VehicleSystemCheckVisitor.java:
--------------------------------------------------------------------------------
1 | class VehicleSystemCheckVisitor implements CheckVisitor{
2 |
3 | @Override
4 | public void visit(EngineCheck engineCheck) {
5 | System.out.println("EngineCheck, ready");
6 | visitBySwitch(engineCheck);
7 | }
8 |
9 | @Override
10 | public void visit(SuspensionCheck suspensionCheck) {
11 | System.out.println("SuspensionCheck, ready");
12 | visitBySwitch(suspensionCheck);
13 | }
14 |
15 | @Override
16 | public void visit(BreaksCheck breaksCheck) {
17 | System.out.println("BreakCheck, ready");
18 | visitBySwitch(breaksCheck);
19 | }
20 |
21 | @Override
22 | public void visit(VehicleCheck vehicleCheck) {
23 | System.out.println("VehicleCheck, ready");
24 | visitBySwitch(vehicleCheck);
25 | }
26 |
27 |
28 | private void visitBySwitch(SystemCheck systemCheck){
29 | switch (systemCheck){
30 | case EngineCheck e -> System.out.println("EngineCheck, ready, double-check, " + e);
31 | case SuspensionCheck s -> System.out.println("SuspensionCheck, ready, double-check, " + s);
32 | case BreaksCheck b -> System.out.println("BreakCheck, ready, double-check, " + b);
33 | case VehicleCheck v -> System.out.println("VehicleCheck, ready, double-check, " + v);
34 | case null -> System.out.println("VehicleSystemCheckVisitor, not allowed");
35 | default -> System.out.println("VehicleSystemCheckVisitor, not implemented");
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Chapter05/visitor/VisitorMain.java:
--------------------------------------------------------------------------------
1 | class VisitorMain {
2 | public static void main(String[] args) {
3 | System.out.println("Visitor Pattern, check vehicle parts");
4 | var vehicleCheck = new VehicleCheck();
5 | vehicleCheck.accept(new VehicleSystemCheckVisitor());
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter06/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
2 |
3 | ### create and open Java Flight Recorder recording
4 | The project contains several ***.jfr** recordings. The file name contains the identifier of the image that was created from this recording. **Java Mission Control version 8.2** was used for image creation purposes. *.jfr files can be opened in the **Java Mission Control application**, which can be downloaded from the links below.
5 |
6 | download links:
7 | - https://github.com/openjdk/jmc
8 | - https://adoptium.net/jmc/
9 |
10 | ```bash
11 | # Starting the JavaFlightRecorder for the patterns
12 | # Recordings are done on Java 17
13 | $ java -XX:StartFlightRecording=filename=.jfr,dumponexit=true,settings=profile
14 | ```
15 | ## Chapter 6 - concurrency pattern examples
16 | ```bash
17 | # Active object
18 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/active_object -sourcepath java -d out/Chapter06/active_object ./Chapter06/active_object/*.java
19 | $ java --enable-preview -cp out/Chapter06/active_object ActiveObjectMain
20 |
21 | # Async method invocation
22 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/async_method -sourcepath java -d out/Chapter06/async_method ./Chapter06/async_method/*.java
23 | $ java --enable-preview -cp out/Chapter06/async_method AsyncMethodMain
24 |
25 | # Balking
26 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/balking -sourcepath java -d out/Chapter06/balking ./Chapter06/balking/*.java
27 | $ java --enable-preview -cp out/Chapter06/balking BalkingMain
28 |
29 | # Double-checked locking
30 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/double_checked -sourcepath java -d out/Chapter06/double_checked ./Chapter06/double_checked/*.java
31 | $ java --enable-preview -cp out/Chapter06/double_checked DoubleCheckedLockingMain
32 |
33 | # Read-write lock
34 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/read_write_lock -sourcepath java -d out/Chapter06/read_write_lock ./Chapter06/read_write_lock/*.java
35 | $ java --enable-preview -cp out/Chapter06/read_write_lock ReadWriteLockMain
36 |
37 | # Producer-consumer
38 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/prod_con -sourcepath java -d out/Chapter06/prod_con ./Chapter06/prod_con/*.java
39 | $ java --enable-preview -cp out/Chapter06/prod_con ProducerConsumerMain
40 |
41 | # Scheduler
42 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/scheduler -sourcepath java -d out/Chapter06/scheduler ./Chapter06/scheduler/*.java
43 |
44 | $ java --enable-preview -cp out/Chapter06/scheduler CustomSchedulerMain
45 | $ java --enable-preview -cp out/Chapter06/scheduler CustomScheduledThreadPoolMain
46 |
47 | # Thread-pool
48 | $ javac --release 17 --enable-preview -g -cp out/Chapter06/thread_pool -sourcepath java -d out/Chapter06/thread_pool ./Chapter06/thread_pool/*.java
49 | $ java --enable-preview -cp out/Chapter06/thread_pool ThreadPoolMain
50 | ```
51 |
--------------------------------------------------------------------------------
/Chapter06/active_object/ActiveObjectMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.TimeUnit;
2 |
3 | class ActiveObjectMain {
4 | public static void main(String[] args) throws Exception {
5 | System.out.println("Active Object Pattern, moving vehicle");
6 | var sportVehicle = new SportVehicle("super_sport");
7 | sportVehicle.move();
8 | sportVehicle.turnOnRadio();
9 | sportVehicle.turnOffRadio();
10 | sportVehicle.turnOnRadio();
11 | sportVehicle.stopVehicle();
12 | sportVehicle.turnOffRadio();
13 | TimeUnit.MILLISECONDS.sleep(400);
14 | System.out.println("ActiveObjectMain, sportVehicle moving:" + sportVehicle.isMoving());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter06/active_object/ActiveObjectUtil.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.TimeUnit;
2 |
3 | final class ActiveObjectUtil {
4 | static void delayMills(int mills){
5 | try {
6 | TimeUnit.MILLISECONDS.sleep(mills);
7 | } catch (InterruptedException e) {
8 | throw new RuntimeException(e);
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter06/active_object/MovingVehicle.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.BlockingDeque;
2 | import java.util.concurrent.LinkedBlockingDeque;
3 | import java.util.concurrent.atomic.AtomicInteger;
4 |
5 | abstract class MovingVehicle {
6 | private static final AtomicInteger COUNTER = new AtomicInteger();
7 | private final BlockingDeque commands;
8 | private final String type;
9 | private final Thread thread;
10 | private boolean active;
11 |
12 | MovingVehicle(String type) {
13 | this.commands = new LinkedBlockingDeque<>();
14 | this.type = type;
15 | this.thread = createMovementThread();
16 | }
17 |
18 | protected boolean isActive() {
19 | return active;
20 | }
21 |
22 | void move() {
23 | active = true;
24 | thread.start();
25 | }
26 |
27 | void turnOnRadio() throws InterruptedException {
28 | commands.putLast(() -> {
29 | ActiveObjectUtil.delayMills(50);
30 | System.out.printf("""
31 | MovingVehicle:'%s', radio on%n""", this.type);
32 | });
33 | }
34 |
35 | void turnOffRadio() throws InterruptedException {
36 | commands.putLast(() -> {
37 | ActiveObjectUtil.delayMills(50);
38 | System.out.printf("""
39 | MovingVehicle:'%s', radio on%n""", this.type);
40 |
41 | });
42 | }
43 |
44 | void stopVehicle() throws InterruptedException {
45 | commands.putFirst(() -> {
46 | this.active = false;
47 | ActiveObjectUtil.delayMills(50);
48 | System.out.printf("""
49 | MovingVehicle:'%s', stopping, commands_active:'%d'%n""", this.type, this.commands.size());
50 | });
51 | }
52 |
53 | private Thread createMovementThread() {
54 | var thread = new Thread(() -> {
55 | while (active) {
56 | try {
57 | var command = commands.take();
58 | System.out.printf("""
59 | MovingVehicle:'%s', moving%n""", this.type);
60 | command.run();
61 | ActiveObjectUtil.delayMills(60);
62 | } catch (InterruptedException e) {
63 | System.err.println(e.getMessage());
64 | active = false;
65 | }
66 | }
67 | System.out.printf("""
68 | MovingVehicle:'%s', stopped%n""", this.type);
69 | });
70 | thread.setDaemon(true);
71 | thread.setName("moving-vehicle-" + COUNTER.getAndIncrement());
72 | return thread;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Chapter06/active_object/SportVehicle.java:
--------------------------------------------------------------------------------
1 | class SportVehicle extends MovingVehicle {
2 | public SportVehicle(String type) {
3 | super(type);
4 | }
5 |
6 | boolean isMoving(){
7 | return isActive();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter06/active_object_figure_6_1.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/active_object_figure_6_1.jfr
--------------------------------------------------------------------------------
/Chapter06/async_method/AsyncMethodMain.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 |
3 | class AsyncMethodMain {
4 | public static void main(String[] args) throws Exception {
5 | System.out.println("Async method invocation Pattern, moving vehicle");
6 | var sensorTaskExecutor = new TempSensorExecutor();
7 | var tempSensorCallback = new TempSensorCallback();
8 |
9 | var tasksNumber = 5;
10 | var measurements = new ArrayList>();
11 | System.out.printf("""
12 | AsyncMethodMain, tasksNumber:'%d' %n""", tasksNumber);
13 | for(int i=0; i {
2 | void onMeasurement(T value);
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter06/async_method/SensorExecutor.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.Callable;
2 |
3 | interface SensorExecutor {
4 | SensorResult measure(Callable sensor, SensorCallback callback);
5 | void start();
6 | T stopMeasurement(SensorResult measurement);
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter06/async_method/SensorResult.java:
--------------------------------------------------------------------------------
1 | interface SensorResult {
2 | boolean isPresent();
3 | void setResult(T value);
4 | T getResult();
5 | void await();
6 | void addException(Throwable e);
7 |
8 | void printExceptions();
9 | }
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Chapter06/async_method/TempSensorCallback.java:
--------------------------------------------------------------------------------
1 | class TempSensorCallback implements SensorCallback{
2 | @Override
3 | public void onMeasurement(Integer value) {
4 | AsyncMethodUtils.delayMills(10);
5 | System.out.printf("""
6 | TemperatureSensorCallback, recorded value:'%d', thread:'%s'%n""", value, Thread.currentThread().getName());
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter06/async_method/TempSensorExecutor.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 | import java.util.concurrent.Callable;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | class TempSensorExecutor implements SensorExecutor {
7 |
8 | private static final AtomicInteger COUNTER = new AtomicInteger();
9 | private final List threads = new ArrayList<>();
10 |
11 | @Override
12 | public SensorResult measure(Callable sensor, SensorCallback callback) {
13 | var result = new TempSensorResult(callback);
14 | Runnable runnable = () -> {
15 | try {
16 | result.setResult(sensor.call());
17 | } catch (Exception e) {
18 | result.addException(e);
19 | }
20 | };
21 | var thread = new Thread(runnable, "thread-" + COUNTER.getAndIncrement());
22 | thread.setDaemon(true);
23 | threads.add(thread);
24 | return result;
25 | }
26 |
27 | @Override
28 | public void start() {
29 | threads.forEach(Thread::start);
30 | System.out.println("SensorTaskExecutor, started:" + threads.size());
31 | }
32 |
33 | @Override
34 | public T stopMeasurement(SensorResult measurement) {
35 | if (!measurement.isPresent()) {
36 | measurement.await();
37 | }
38 | return measurement.getResult();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Chapter06/async_method/TempSensorResult.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | class TempSensorResult implements SensorResult{
5 |
6 | private final List exceptions = new ArrayList<>();
7 | private final SensorCallback callback;
8 | private T value;
9 |
10 | public TempSensorResult(SensorCallback callback) {
11 | this.callback = callback;
12 | }
13 |
14 | @Override
15 | public boolean isPresent() {
16 | return value != null;
17 | }
18 |
19 | @Override
20 | public void setResult(T value) {
21 | this.value = value;
22 | }
23 |
24 | @Override
25 | public T getResult() {
26 |
27 | callback.onMeasurement(value);
28 | return value;
29 | }
30 |
31 | @Override
32 | public void await() {
33 | AsyncMethodUtils.delayMills(2);
34 | }
35 |
36 | @Override
37 | public void addException(Throwable t) {
38 | exceptions.add(t);
39 | }
40 |
41 | @Override
42 | public void printExceptions() {
43 | exceptions.stream().map(Throwable::getMessage).forEach(System.out::println);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Chapter06/async_method/TempSensorTask.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 | import java.util.concurrent.Callable;
3 | import java.util.concurrent.atomic.AtomicInteger;
4 |
5 | class TempSensorTask implements Callable {
6 | private static final Random RANDOM = new Random();
7 | private static final AtomicInteger COUNTER = new AtomicInteger();
8 | @Override
9 | public Integer call() throws Exception {
10 | var temperature = RANDOM.nextInt(0, 42);
11 | AsyncMethodUtils.delayMills(10);
12 | System.out.printf("TempSensorTask,n:'%d' temp:'%d', thread:'%s'%n", COUNTER.getAndIncrement(), temperature, Thread.currentThread().getName());
13 | return temperature;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter06/async_method_figure_6_3.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/async_method_figure_6_3.jfr
--------------------------------------------------------------------------------
/Chapter06/balking/BalkingMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.Executors;
2 | import java.util.concurrent.TimeUnit;
3 |
4 | class BalkingMain {
5 | public static void main(String[] args) throws Exception {
6 | System.out.println("Balking pattern, vehicle move");
7 |
8 | var vehicle = new Vehicle();
9 | var numberOfDrivers = 5;
10 | var executors = Executors.newFixedThreadPool(2);
11 | for (int i = 0; i < numberOfDrivers; i++) {
12 | executors.submit(vehicle::drive);
13 | }
14 | TimeUnit.MILLISECONDS.sleep(1000);
15 | executors.shutdown();
16 | System.out.println("Done");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Chapter06/balking/Vehicle.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 | import java.util.concurrent.TimeUnit;
3 |
4 | class Vehicle {
5 | private static final Random RANDOM = new Random();
6 | private VehicleState state;
7 |
8 | public Vehicle() {
9 | }
10 |
11 | private void init() {
12 | stop();
13 | }
14 |
15 | private synchronized void stop(){
16 | state = VehicleState.STOPPED;
17 | }
18 |
19 | void drive() {
20 | try {
21 | driveWithMills(RANDOM.nextInt(50,100));
22 | } catch (InterruptedException e) {
23 | throw new RuntimeException(e);
24 | }
25 | }
26 |
27 | synchronized void driveWithMills(int mills) throws InterruptedException {
28 | var internalState = getState();
29 | switch (internalState) {
30 | case MOVING -> System.out.printf("""
31 | Vehicle state:'%s', vehicle in move, millis:'%d', thread='%s'%n""", state, mills, Thread.currentThread());
32 | case STOPPED -> startEngineAndMove(mills);
33 | case null -> init();
34 | }
35 |
36 | }
37 |
38 | private VehicleState getState(){
39 | return state;
40 | }
41 |
42 | private void startEngineAndMove(int mills) throws InterruptedException {
43 | state = VehicleState.MOVING;
44 | System.out.printf("""
45 | Vehicle state:'%s', moving, mills:'%d', thread='%s'%n""", state, mills, Thread.currentThread());
46 | TimeUnit.MILLISECONDS.sleep(mills);
47 | stop();
48 | System.out.printf("""
49 | Vehicle state:'%s' stopped, mills:'%d', thread='%s'%n""", state, mills, Thread.currentThread());
50 |
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/Chapter06/balking/VehicleState.java:
--------------------------------------------------------------------------------
1 | enum VehicleState {
2 | MOVING,
3 | STOPPED,
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter06/balking_figure_6_5.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/balking_figure_6_5.jfr
--------------------------------------------------------------------------------
/Chapter06/double_checked/DoubleCheckedLockingMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.ExecutorService;
2 | import java.util.concurrent.Executors;
3 |
4 | class DoubleCheckedLockingMain {
5 | public static void main(String[] args) {
6 | System.out.println("Double checked locking pattern, only one vehicle");
7 | var amount = 5;
8 | ExecutorService executor = Executors.newFixedThreadPool(amount);
9 | System.out.println("Number of executors:" + amount);
10 | for (int i = 0; i < amount; i++) {
11 | executor.submit(VehicleSingleton::getInstance);
12 | executor.submit(VehicleSingletonChecked::getInstance);
13 | }
14 | executor.shutdown();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter06/double_checked/Vehicle.java:
--------------------------------------------------------------------------------
1 | sealed interface Vehicle permits VehicleSingleton, VehicleSingletonChecked {
2 | String type();
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter06/double_checked/VehicleSingleton.java:
--------------------------------------------------------------------------------
1 | final class VehicleSingleton implements Vehicle{
2 | private static VehicleSingleton INSTANCE;
3 | public static VehicleSingleton getInstance(){
4 | if(INSTANCE == null){
5 | INSTANCE = new VehicleSingleton();
6 | }
7 | return INSTANCE;
8 | }
9 |
10 | private final String type;
11 |
12 | VehicleSingleton() {
13 | this.type = Thread.currentThread().getName();
14 | System.out.printf("""
15 | VehicleSingleton, constructor thread:'%s' hashCode:'%s'%n""", type, this.hashCode());
16 | }
17 |
18 | @Override
19 | public String type() {
20 | return type;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter06/double_checked/VehicleSingletonChecked.java:
--------------------------------------------------------------------------------
1 | final class VehicleSingletonChecked implements Vehicle {
2 |
3 | private static VehicleSingletonChecked INSTANCE;
4 |
5 | static VehicleSingletonChecked getInstance() {
6 | if (INSTANCE == null) {
7 | synchronized (VehicleSingletonChecked.class) {
8 | if (INSTANCE == null) {
9 | INSTANCE = new VehicleSingletonChecked();
10 | }
11 | }
12 | }
13 | return INSTANCE;
14 | }
15 |
16 | private final String type;
17 |
18 | VehicleSingletonChecked() {
19 | this.type = Thread.currentThread().getName();
20 | System.out.printf("""
21 | VehicleSingletonChecked, constructor thread:'%s' hashCode:'%s'%n""", type, this.hashCode());
22 | }
23 |
24 | @Override
25 | public String type() {
26 | return type;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Chapter06/double_checked_figure_6_7.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/double_checked_figure_6_7.jfr
--------------------------------------------------------------------------------
/Chapter06/prod_con/Event.java:
--------------------------------------------------------------------------------
1 | record Event(int number, String source) {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter06/prod_con/EventConsumer.java:
--------------------------------------------------------------------------------
1 | class EventConsumer implements Runnable {
2 | private final int number;
3 | private final EventsContainer container;
4 |
5 | EventConsumer(int number, EventsContainer container) {
6 | this.number = number;
7 | this.container = container;
8 | }
9 |
10 | @Override
11 | public void run() {
12 | var even = container.getEvent();
13 | System.out.printf("""
14 | VehicleSecurityConsumer,event:'%s', number:'%d', thread:'%s'%n""", even, number, Thread.currentThread().getName());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter06/prod_con/EventProducer.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 | import java.util.concurrent.atomic.AtomicInteger;
3 |
4 | class EventProducer implements Runnable{
5 |
6 | private static final AtomicInteger COUNTER = new AtomicInteger();
7 | private static final Random RANDOM = new Random();
8 | private final EventsContainer container;
9 |
10 | EventProducer(EventsContainer container) {
11 | this.container = container;
12 | }
13 |
14 | @Override
15 | public void run() {
16 | var delay = RANDOM.nextInt(20,50);
17 | var event = new Event(COUNTER.getAndIncrement(), Thread.currentThread().getName());
18 | container.putEvent(event);
19 | ProducerConsumerUtil.delayMills(delay);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Chapter06/prod_con/EventsContainer.java:
--------------------------------------------------------------------------------
1 | import java.util.Queue;
2 | import java.util.concurrent.ArrayBlockingQueue;
3 | import java.util.concurrent.locks.Condition;
4 | import java.util.concurrent.locks.ReentrantLock;
5 |
6 | class EventsContainer {
7 |
8 | private final ReentrantLock lock;
9 | private final Condition containerFull;
10 | private final Condition containerReady;
11 | private final Queue storage;
12 | private final int maxSize;
13 |
14 | EventsContainer(int size) {
15 | this.lock = new ReentrantLock();
16 | this.containerFull = lock.newCondition();
17 | this.containerReady = lock.newCondition();
18 | this.maxSize = size;
19 | this.storage = new ArrayBlockingQueue<>(maxSize);
20 | }
21 |
22 | void putEvent(Event event){
23 | lock.lock();
24 | try {
25 | while (storage.size() == maxSize) containerFull.await();
26 | storage.add(event);
27 | containerReady.signal();
28 | } catch (InterruptedException e){
29 | throw new RuntimeException(e);
30 | } finally {
31 | lock.unlock();
32 | }
33 | }
34 |
35 | Event getEvent(){
36 | lock.lock();
37 | try {
38 | while(storage.peek() == null) containerReady.await();
39 | var result = storage.poll();
40 | containerFull.signal();
41 | return result;
42 | } catch (InterruptedException e){
43 | throw new RuntimeException(e);
44 | } finally {
45 | lock.unlock();
46 | }
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/Chapter06/prod_con/ProdConThreadFactory.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.ThreadFactory;
2 | import java.util.concurrent.atomic.AtomicInteger;
3 |
4 | class ProdConThreadFactory implements ThreadFactory {
5 |
6 | private final AtomicInteger counter;
7 | private final String name;
8 |
9 | ProdConThreadFactory(String name) {
10 | this.counter = new AtomicInteger();
11 | this.name = name;
12 | }
13 |
14 | @Override
15 | public Thread newThread(Runnable r) {
16 | var t = new Thread(r);
17 | t.setDaemon(true);
18 | t.setName("""
19 | pool-%s-%d""".formatted(name, counter.getAndIncrement()));
20 | return t;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter06/prod_con/ProducerConsumerMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.ExecutorService;
2 | import java.util.concurrent.Executors;
3 | import java.util.concurrent.TimeUnit;
4 | import java.util.stream.IntStream;
5 |
6 | class ProducerConsumerMain {
7 | public static void main(String[] args) throws Exception{
8 | System.out.println("Producer-Consumer pattern, decoupling receiver and emitters");
9 | var producersNumber = 12;
10 | var consumersNumber = 10;
11 | var container = new EventsContainer(3);
12 |
13 | ExecutorService producerExecutor = Executors.newFixedThreadPool(4, new ProdConThreadFactory("prod"));
14 | ExecutorService consumersExecutor = Executors.newFixedThreadPool(2, new ProdConThreadFactory("con"));
15 | IntStream.range(0, producersNumber)
16 | .boxed().map(i -> new EventProducer(container))
17 | .forEach(producerExecutor::submit);
18 | IntStream.range(0, consumersNumber)
19 | .boxed().map(i -> new EventConsumer(i,container))
20 | .forEach(consumersExecutor::submit);
21 | TimeUnit.MILLISECONDS.sleep(200);
22 | producerExecutor.shutdown();
23 | consumersExecutor.shutdown();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter06/prod_con/ProducerConsumerUtil.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.TimeUnit;
2 |
3 | final class ProducerConsumerUtil {
4 | static void delayMills(int mills){
5 | try {
6 | TimeUnit.MILLISECONDS.sleep(mills);
7 | } catch (InterruptedException e) {
8 | throw new RuntimeException(e);
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter06/prod_con_figure_6_11.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/prod_con_figure_6_11.jfr
--------------------------------------------------------------------------------
/Chapter06/read_write_lock/ReadWriteLockMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.ExecutorService;
2 | import java.util.concurrent.Executors;
3 | import java.util.concurrent.locks.ReentrantReadWriteLock;
4 | import java.util.stream.IntStream;
5 |
6 | class ReadWriteLockMain {
7 | private static final int NUMBER_READERS = 3;
8 | private static final int CYCLES_READER = 10;
9 |
10 | public static void main(String[] args) throws Exception {
11 | System.out.println("Read-Write Lock pattern, writing and reading sensor values");
12 | ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
13 | var sensor = new Sensor(readWriteLock.readLock(), readWriteLock.writeLock());
14 | var sensorWriter = new SensorWriter("writer-1", sensor);
15 | var writerThread = getWriterThread(sensorWriter);
16 |
17 | ExecutorService executor = Executors.newFixedThreadPool(NUMBER_READERS);
18 | var readers = IntStream.range(0, NUMBER_READERS)
19 | .boxed().map(i -> new SensorReader("reader-" + i, sensor, CYCLES_READER)).toList();
20 | readers.forEach(executor::submit);
21 | writerThread.start();
22 | executor.shutdown();
23 | }
24 |
25 | private static Thread getWriterThread(SensorWriter sensorWriter) {
26 | var writerThread = new Thread(sensorWriter);
27 | writerThread.setName("pool-2-writer-1");
28 | writerThread.setDaemon(true);
29 | return writerThread;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Chapter06/read_write_lock/ReadWriteLockUtils.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.TimeUnit;
2 |
3 | final class ReadWriteLockUtils {
4 | private ReadWriteLockUtils(){};
5 | static void delayMills(int mills){
6 | try {
7 | TimeUnit.MILLISECONDS.sleep(mills);
8 | } catch (InterruptedException e) {
9 | throw new RuntimeException(e);
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter06/read_write_lock/Sensor.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
2 | import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
3 |
4 | class Sensor {
5 | private final ReadLock readLock;
6 | private final WriteLock writeLock;
7 | private int value = 50;
8 |
9 | Sensor(ReadLock readLock, WriteLock writeLock) {
10 | this.readLock = readLock;
11 | this.writeLock = writeLock;
12 | }
13 |
14 | int getValue() {
15 | readLock.lock();
16 | int result;
17 | try {
18 | result = value;
19 | ReadWriteLockUtils.delayMills(result);
20 | } finally {
21 | readLock.unlock();
22 | }
23 | return result;
24 | }
25 |
26 | void writeValue(int v) {
27 | writeLock.lock();
28 | try {
29 | this.value = v;
30 | ReadWriteLockUtils.delayMills(v);
31 | } finally {
32 | writeLock.unlock();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Chapter06/read_write_lock/SensorReader.java:
--------------------------------------------------------------------------------
1 | class SensorReader implements Runnable {
2 |
3 | private final String type;
4 | private final Sensor sensor;
5 | private final int cycles;
6 |
7 | SensorReader(String type, Sensor sensor, int cycles) {
8 | this.type = type;
9 | this.sensor = sensor;
10 | this.cycles = cycles;
11 | }
12 |
13 | @Override
14 | public void run() {
15 | for(int i=0; i < cycles; i++){
16 | var value = sensor.getValue();
17 | System.out.printf("""
18 | SensorReader read, type:'%s', value:'%d, thread:'%s'%n""", type, value, Thread.currentThread().getName());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Chapter06/read_write_lock/SensorWriter.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 |
3 | class SensorWriter implements Runnable {
4 | private static final Random RANDOM = new Random();
5 | private final String type;
6 | private final Sensor sensor;
7 |
8 | SensorWriter(String type, Sensor sensor) {
9 | this.type = type;
10 | this.sensor = sensor;
11 | }
12 |
13 | @Override
14 | public void run() {
15 | var value = RANDOM.nextInt(10, 30);
16 | sensor.writeValue(value);
17 | ReadWriteLockUtils.delayMills(value);
18 | System.out.printf("""
19 | SensorWriter write, type:'%s', value:'%d', thread:'%s'%n""", type, value, Thread.currentThread().getName());
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter06/read_write_lock/read_write_lock_figure_6_9.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/read_write_lock/read_write_lock_figure_6_9.jfr
--------------------------------------------------------------------------------
/Chapter06/scheduler/CustomScheduledThreadPoolExecutor.java:
--------------------------------------------------------------------------------
1 | import java.time.LocalDateTime;
2 | import java.time.temporal.ChronoUnit;
3 | import java.util.Map;
4 | import java.util.concurrent.ConcurrentHashMap;
5 | import java.util.concurrent.ScheduledFuture;
6 | import java.util.concurrent.ScheduledThreadPoolExecutor;
7 | import java.util.concurrent.TimeUnit;
8 | import java.util.concurrent.atomic.AtomicInteger;
9 |
10 | class CustomScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
11 |
12 | private static final AtomicInteger COUNTER = new AtomicInteger();
13 | private final Map startTimestamps = new ConcurrentHashMap<>();
14 |
15 | CustomScheduledThreadPoolExecutor(int corePoolSize) {
16 | super(corePoolSize, r -> {
17 | var thread = new Thread(r, "custom-scheduler-pool-"+ COUNTER.getAndIncrement());
18 | thread.setDaemon(true);
19 | return thread;
20 | });
21 | }
22 |
23 | @Override
24 | protected void beforeExecute(Thread t, Runnable r) {
25 | System.out.printf("""
26 | POOL, before execution, thread:'%s', task:'%s'%n""", t.getName(), r.hashCode());
27 | startTimestamps.put(r.hashCode(), LocalDateTime.now());
28 | }
29 |
30 | @Override
31 | protected void afterExecute(Runnable r, Throwable t) {
32 | var startTime = startTimestamps.get(r.hashCode());
33 | var diff = ChronoUnit.MILLIS.between(startTime, LocalDateTime.now());
34 | System.out.printf("""
35 | POOL, after execution, task:'%s', diff:'%d'%n""", r.hashCode(), diff);
36 | }
37 |
38 | @Override
39 | public ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
40 | var mills = TimeUnit.MILLISECONDS.convert(period, unit);
41 | ScheduledFuture> result = super.scheduleAtFixedRate(command, initialDelay, mills, TimeUnit.MILLISECONDS);
42 | System.out.printf("""
43 | POOL: scheduled task:'%s', every MILLS:'%d'%n""", command.hashCode(), mills);
44 | return result;
45 | }
46 |
47 | @Override
48 | public void shutdown() {
49 | System.out.println("POOL is going down");
50 | super.shutdown();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Chapter06/scheduler/CustomScheduledThreadPoolMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.TimeUnit;
2 |
3 | class CustomScheduledThreadPoolMain {
4 | public static void main(String[] args) throws Exception {
5 | System.out.println("Pooled scheduler pattern , providing sensor values");
6 | var pool = new CustomScheduledThreadPoolExecutor(2);
7 |
8 | for(int i=0; i < 4; i++){
9 | pool.scheduleAtFixedRate(new SensorTask("temperature-"+i), 0, 50, TimeUnit.MILLISECONDS);
10 | }
11 | TimeUnit.MILLISECONDS.sleep(600);
12 | pool.shutdown();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter06/scheduler/CustomScheduler.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.ArrayBlockingQueue;
2 | import java.util.concurrent.TimeUnit;
3 |
4 | class CustomScheduler {
5 |
6 | private final int intervalMills;
7 | private final Thread thread;
8 | private final ArrayBlockingQueue queue;
9 | private boolean active;
10 |
11 | CustomScheduler(int intervalMillis) {
12 | this.intervalMills = intervalMillis;
13 | this.queue = new ArrayBlockingQueue<>(10);
14 | this.thread = new Thread(() -> {
15 | while (active){
16 | try {
17 | var runnable = queue.poll(intervalMillis, TimeUnit.MILLISECONDS);
18 | if(runnable != null){
19 | runnable.run();
20 | }
21 | var delay = intervalMillis - runnable.activeTime();
22 | TimeUnit.MILLISECONDS.sleep(delay);
23 | } catch (InterruptedException e) {
24 | throw new RuntimeException(e);
25 | }
26 | }
27 | System.out.println("CustomScheduler, stopped");
28 | }, "scheduler-1");
29 | }
30 |
31 | void run(){
32 | this.active = true;
33 | this.thread.start();
34 | }
35 |
36 | void stop(){
37 | this.active = false;
38 | }
39 |
40 |
41 | void addTask(SensorTask runnable){
42 | try {
43 | queue.put(runnable);
44 | } catch (InterruptedException e) {
45 | throw new RuntimeException(e);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Chapter06/scheduler/CustomSchedulerMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.TimeUnit;
2 |
3 | class CustomSchedulerMain {
4 | public static void main(String[] args) throws Exception {
5 | System.out.println("Scheduler pattern, temperatures measurement");
6 | var scheduler = new CustomScheduler(100);
7 | scheduler.run();
8 | for(int i=0; i < 15; i++){
9 | scheduler.addTask(new SensorTask("temperature-"+i));
10 | }
11 |
12 | TimeUnit.SECONDS.sleep(1);
13 | scheduler.stop();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter06/scheduler/SensorTask.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 | import java.util.concurrent.TimeUnit;
3 |
4 | class SensorTask implements Runnable {
5 | private final Random random;
6 | private final String type;
7 | private int activeTime;
8 |
9 | SensorTask(String type) {
10 | this.random = new Random();
11 | this.type = type;
12 | }
13 |
14 | int activeTime() {
15 | return activeTime;
16 | }
17 |
18 | @Override
19 | public void run() {
20 | activeTime = random.nextInt(50, 80);
21 | try {
22 | System.out.printf("""
23 | SensorTask, type:'%s',activeTime:'%d',thread:'%s'%n""", type, activeTime, Thread.currentThread().getName());
24 | TimeUnit.MILLISECONDS.sleep(activeTime);
25 | } catch (InterruptedException e) {
26 | throw new RuntimeException(e);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Chapter06/scheduler_custom_figure_6_13.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/scheduler_custom_figure_6_13.jfr
--------------------------------------------------------------------------------
/Chapter06/scheduler_pool_figure_6_15.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/scheduler_pool_figure_6_15.jfr
--------------------------------------------------------------------------------
/Chapter06/thread_pool/SensorTask.java:
--------------------------------------------------------------------------------
1 | sealed interface SensorTask permits TemperatureTask {
2 | void measure() throws InterruptedException;
3 | }
4 |
--------------------------------------------------------------------------------
/Chapter06/thread_pool/SensorWorker.java:
--------------------------------------------------------------------------------
1 | class SensorWorker implements Runnable {
2 | private final SensorTask task;
3 |
4 | SensorWorker(SensorTask task) {
5 | this.task = task;
6 | }
7 |
8 | @Override
9 | public void run() {
10 | try {
11 | task.measure();
12 | } catch (InterruptedException e) {
13 | throw new RuntimeException(e);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter06/thread_pool/TemperatureTask.java:
--------------------------------------------------------------------------------
1 | import java.util.Random;
2 | import java.util.concurrent.TimeUnit;
3 |
4 | final class TemperatureTask implements SensorTask{
5 | private static final Random RANDOM = new Random();
6 |
7 | private final String type;
8 |
9 | public TemperatureTask(String type) {
10 | this.type = type;
11 | }
12 |
13 | @Override
14 | public void measure() throws InterruptedException {
15 | var temperature = RANDOM.nextInt(0,42);
16 | TimeUnit.MILLISECONDS.sleep(temperature);
17 | System.out.printf("""
18 | TemperatureTask, type:'%s', temp:'%s', thread:'%s'%n""", type, temperature, Thread.currentThread().getName());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Chapter06/thread_pool/ThreadPoolMain.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.Executors;
2 |
3 | class ThreadPoolMain {
4 | public static void main(String[] args) throws Exception{
5 | System.out.println("Thread-Pool pattern, providing sensor values");
6 | var executor = Executors.newFixedThreadPool(5);
7 |
8 | for(int i=0; i < 15; i++){
9 | var task = new TemperatureTask("temp" + i);
10 | var worker = new SensorWorker(task);
11 | executor.submit(worker);
12 | }
13 | executor.shutdown();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter06/thread_pool_figure_6_17.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter06/thread_pool_figure_6_17.jfr
--------------------------------------------------------------------------------
/Chapter07/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
2 |
3 | ### create and open Java Flight Recorder recording
4 | The project contains several ***.jfr** recordings. The file name contains the identifier of the image that was created from this recording. **Java Mission Control version 8.2** was used for image creation purposes. *.jfr files can be opened in the **Java Mission Control application**, which can be downloaded from the links below.
5 |
6 | download links:
7 | - https://github.com/openjdk/jmc
8 | - https://adoptium.net/jmc/
9 |
10 | ```bash
11 | # Starting the JavaFlightRecorder for the patterns
12 | # Recordings are done on Java 17
13 | $ java -XX:StartFlightRecording=filename=.jfr,dumponexit=true,settings=profile
14 | ```
15 | ## Chapter 7 - anti-patterns exmples
16 | ```bash
17 | # Garbage collection phenomenon
18 | $ javac --release 17 --enable-preview -g -cp out/Chapter07/garbage -sourcepath java -d out/Chapter07/garbage ./Chapter07/garbage/*.java
19 | $ java --enable-preview -cp out/Chapter07/garbage GarbageMain
20 |
21 |
22 | # Busy method phenomenon
23 | $ javac --release 17 --enable-preview -g -cp out/Chapter07/busy_method -sourcepath java -d out/Chapter07/busy_method ./Chapter07/busy_method/*.java
24 | $ java --enable-preview -cp out/Chapter07/busy_method BusyMethodMain
25 | ```
26 |
--------------------------------------------------------------------------------
/Chapter07/anti_patterns/VehicleBlob.java:
--------------------------------------------------------------------------------
1 | class VehicleBlob {
2 | void drive(){}
3 | void initEngine(){}
4 | void checkFuel(){}
5 | void alarmOilLevel(){}
6 | void runCylinder() {}
7 | void checkCylinderHead(){}
8 | void checkWaterPump(){}
9 | }
10 |
--------------------------------------------------------------------------------
/Chapter07/anti_patterns/VehicleCO.java:
--------------------------------------------------------------------------------
1 | interface VehicleCO {
2 | void checkEngine();
3 | void initSystem();
4 | void initRadio(); /* never used */
5 | void initCassettePlayer(); /* never used */
6 | void initMediaSystem(); /* actual logic */
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter07/anti_patterns/VehicleCOImpl.java:
--------------------------------------------------------------------------------
1 | class VehicleCOImpl implements VehicleCO{
2 | @Override
3 | public void checkEngine() {
4 |
5 | }
6 |
7 | @Override
8 | public void initSystem() {
9 |
10 | }
11 |
12 | @Override
13 | public void initRadio() {
14 | /* never used */
15 | }
16 |
17 | @Override
18 | public void initCassettePlayer() {
19 | /* never used */
20 | }
21 |
22 | @Override
23 | public void initMediaSystem() {
24 | /* actual logic */
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Chapter07/anti_patterns/VehicleSpaghetti.java:
--------------------------------------------------------------------------------
1 | class VehicleSpaghetti {
2 | void drive(){
3 | /*
4 | around 100 lines of code
5 | heavily using the if-else construct
6 | */
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter07/busy_method/BusyMethodMain.java:
--------------------------------------------------------------------------------
1 | import java.io.IOException;
2 | import java.util.HashSet;
3 |
4 | class BusyMethodMain {
5 |
6 | static final int THREADS_NUMBER = 4;
7 | static final int ELEMENTS_NUMBER = 1000;
8 |
9 | public static void main(String[] args) throws IOException {
10 | System.out.println("Vehicle Data Analysis Example...");
11 | var builder = new ThreadContainer.Builder()
12 | .addThreadGroup("Busy-Method-Workers");
13 | for (int i = 0; i < THREADS_NUMBER; i++) {
14 | builder.addRunnable(new VehicleAnalyticalWorker(i, ELEMENTS_NUMBER, new HashSet<>(), new HashSet<>()));
15 | }
16 | var container = builder.build();
17 |
18 | container.startAsDaemon();
19 | System.out.println("ThreadContainer started:" + container.isStarted() + ", threads:" + THREADS_NUMBER);
20 | System.out.println("Press any key to quit!");
21 | System.out.flush();
22 | System.in.read();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Chapter07/busy_method/ThreadContainer.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | class ThreadContainer {
5 |
6 | static final class Builder {
7 |
8 | private ThreadGroup threadGroup = new ThreadGroup("Workers");
9 | private int threadsNumber = 0;
10 | private final ThreadContainer container;
11 |
12 | Builder(){
13 | this.container = new ThreadContainer();
14 | }
15 |
16 | Builder addThreadGroup(String name) {
17 | this.threadGroup = new ThreadGroup(name);
18 | return this;
19 | }
20 |
21 | Builder addRunnable(Runnable r) {
22 | container.addRunnable(threadGroup, r, threadsNumber++);
23 | return this;
24 | }
25 |
26 | ThreadContainer build() {
27 | return container;
28 | }
29 |
30 | }
31 |
32 | private final List list = new ArrayList<>();
33 | private boolean started;
34 |
35 | private ThreadContainer(){}
36 |
37 | void addRunnable(ThreadGroup g, Runnable r, int number){
38 | list.add(new Thread(g, r, g.getName() + "-" + number));
39 | }
40 |
41 | void startAsDaemon(){
42 | if(!started){
43 | System.out.println("Container started!");
44 | for(Thread t: list){
45 | t.setDaemon(true);
46 | t.start();
47 | }
48 | started = true;
49 | } else {
50 | System.out.println("Container started");
51 | }
52 | }
53 |
54 | boolean isStarted() {
55 | return started;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Chapter07/busy_method/VehicleAnalyticalWorker.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 |
3 | class VehicleAnalyticalWorker implements Runnable {
4 |
5 | private final int id;
6 | private final int elementsNumber;
7 | private final Collection c1;
8 | private final Collection c2;
9 | private boolean active;
10 |
11 | public VehicleAnalyticalWorker(int id, int elementsNumber, Collection c1, Collection c2) {
12 | this.id = id;
13 | this.elementsNumber = elementsNumber;
14 | this.c1 = c1;
15 | this.c2 = c2;
16 | this.active =true;
17 | }
18 |
19 |
20 | @Override
21 | public void run() {
22 | while (active) {
23 | VehicleAnalyticalWorkerEvent event = new VehicleAnalyticalWorkerEvent(id);
24 | event.begin();
25 | VehicleDataContainer vc1 = new VehicleDataContainer(elementsNumber, c1);
26 | VehicleDataContainer vc2 = new VehicleDataContainer(elementsNumber, c2);
27 |
28 | vc1.init(5);
29 | vc2.init(7);
30 |
31 | int countIntersections = vc1.countIntersections(vc2);
32 | event.setIntersectionSize(countIntersections);
33 | event.commit();
34 | Thread.yield();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Chapter07/busy_method/VehicleAnalyticalWorkerEvent.java:
--------------------------------------------------------------------------------
1 | import jdk.jfr.Category;
2 | import jdk.jfr.Description;
3 | import jdk.jfr.Event;
4 | import jdk.jfr.Label;
5 | import jdk.jfr.Name;
6 |
7 | @Name("busy_method.VehicleAnalyticalWorkerEvent")
8 | @Label("VehicleAnalyticalWorker")
9 | @Category("Busy Method")
10 | @Description("Analytical Worker")
11 | public class VehicleAnalyticalWorkerEvent extends Event {
12 | @Label("AnalyticalWorker-id")
13 | @Description("id")
14 | private int id;
15 | @Label("measured size")
16 | @Description("batch size")
17 | private int intersectionSize;
18 |
19 | public VehicleAnalyticalWorkerEvent(Integer id) {
20 | this.id = id;
21 | }
22 |
23 | public void setId(int id) {
24 | this.id = id;
25 | }
26 |
27 | public Integer getId() {
28 | return id;
29 | }
30 |
31 | public void setId(Integer id) {
32 | this.id = id;
33 | }
34 |
35 | public int getIntersectionSize() {
36 | return intersectionSize;
37 | }
38 |
39 | public void setIntersectionSize(int intersectionSize) {
40 | this.intersectionSize = intersectionSize;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Chapter07/busy_method/VehicleDataContainer.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 |
3 | class VehicleDataContainer {
4 |
5 | private final int maxElements;
6 | private final Collection collection;
7 |
8 | VehicleDataContainer(int maxElements, Collection collection) {
9 | this.maxElements = maxElements;
10 | this.collection = collection;
11 | }
12 |
13 |
14 | void init(int modulo) {
15 | collection.clear();
16 | for (int i = 0; i < maxElements; i++) {
17 | if (i % modulo != 0) collection.add(i);
18 | }
19 | }
20 |
21 | Collection getCollection() {
22 | return collection;
23 | }
24 |
25 | public int countIntersections(VehicleDataContainer c) {
26 | int count = 0;
27 | for (int n : collection) {
28 | if (c.getCollection().contains(n)) {
29 | count++;
30 | }
31 | }
32 | return count;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Chapter07/busy_method_vehicle_data_analyzer_figure_7_3_corrupted.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter07/busy_method_vehicle_data_analyzer_figure_7_3_corrupted.jfr
--------------------------------------------------------------------------------
/Chapter07/busy_method_vehicle_data_analyzer_figure_7_4_corrected.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter07/busy_method_vehicle_data_analyzer_figure_7_4_corrected.jfr
--------------------------------------------------------------------------------
/Chapter07/garbage/GarbageMain.java:
--------------------------------------------------------------------------------
1 | public class GarbageMain {
2 |
3 | public static final int THREADS_NUMBER = 2;
4 | public static final int ALLOCATION_SIZE = 10_000;
5 |
6 | public static void main(String[] args) throws Exception {
7 | System.out.println("Sensor Alarm example...");
8 | var builder = new ThreadContainer.Builder()
9 | .addThreadGroup("SensorAlarm-Workers");
10 | for (int i = 0; i < THREADS_NUMBER; i++) {
11 | builder.addRunnable(new SensorAlarmWorker(i, ALLOCATION_SIZE));
12 | }
13 |
14 | var container = builder.build();
15 | container.startAsDaemon();
16 | System.out.println("Vehicle alarm system started status:" + container.isStarted() + ", threads:" + THREADS_NUMBER);
17 | System.out.println("Press any key to quit!");
18 | System.out.flush();
19 | System.in.read();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Chapter07/garbage/Sensor.java:
--------------------------------------------------------------------------------
1 | record Sensor(Integer value) {
2 | }
3 |
--------------------------------------------------------------------------------
/Chapter07/garbage/SensorAlarmSystemUtil.java:
--------------------------------------------------------------------------------
1 | import java.util.HashMap;
2 | import java.util.Map;
3 |
4 | final class SensorAlarmSystemUtil {
5 | static void evaluateAlarm(Map storage, Integer criticalValue, long measurementNumber) {
6 | if (!storage.containsKey(criticalValue)) {
7 | System.out.println("WARNING, SensorAlarmWorker criticalValue i:"+ criticalValue +" not present!");
8 | }
9 | if (++measurementNumber % 1000 == 0) {
10 | Thread.yield();
11 | }
12 | }
13 |
14 | static Map createMeasurementResutlMap(int size) {
15 | Map result = new HashMap<>();
16 | for (int i = 0; i < size; i++) {
17 | result.put(i, new Sensor(i));
18 | }
19 | return result;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter07/garbage/SensorAlarmWorker.java:
--------------------------------------------------------------------------------
1 | import java.util.Collection;
2 | import java.util.Map;
3 |
4 |
5 | class SensorAlarmWorker implements Runnable {
6 | private final Map provider;
7 | private final int id;
8 | private boolean active;
9 |
10 | SensorAlarmWorker(int id, int size) {
11 | this.id = id;
12 | this.provider = SensorAlarmSystemUtil.createMeasurementResutlMap(size);
13 | this.active = true;
14 | }
15 |
16 | @Override
17 | public void run() {
18 | long measurementCount = 0;
19 | while (active) {
20 | SensorAlarmWorkerEvent event = new SensorAlarmWorkerEvent(id);
21 | event.begin();
22 | Collection set = provider.values();
23 | for (Sensor e : set) {
24 | SensorAlarmSystemUtil.evaluateAlarm(provider, e.value(), measurementCount);
25 | }
26 | event.commit();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Chapter07/garbage/SensorAlarmWorkerEvent.java:
--------------------------------------------------------------------------------
1 | import jdk.jfr.Category;
2 | import jdk.jfr.Description;
3 | import jdk.jfr.Event;
4 | import jdk.jfr.Label;
5 | import jdk.jfr.Name;
6 |
7 | @Name("garbage.SensorAlarmWorkerEvent")
8 | @Label("SensorAlarm_Worker")
9 | @Category("SensorAlarm_Example")
10 | @Description("measurement values")
11 | public class SensorAlarmWorkerEvent extends Event {
12 |
13 | @Label("SensorAlarm_value")
14 | @Description("SensorAlarm_value")
15 | private Integer value;
16 |
17 | public SensorAlarmWorkerEvent(Integer value) {
18 | this.value = value;
19 | }
20 |
21 | public Integer getValue() {
22 | return value;
23 | }
24 |
25 | public void setValue(Integer value) {
26 | this.value = value;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Chapter07/garbage/ThreadContainer.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | final class ThreadContainer {
5 |
6 | public static final class Builder {
7 |
8 | private ThreadGroup threadGroup = new ThreadGroup("SensorAlarmWorkers");
9 | private int threadsNumber = 0;
10 | private final ThreadContainer container;
11 |
12 | public Builder() {
13 | this.container = new ThreadContainer();
14 | }
15 |
16 | public Builder addThreadGroup(String name) {
17 | this.threadGroup = new ThreadGroup(name);
18 | return this;
19 | }
20 |
21 | public void addRunnable(Runnable r) {
22 | container.addRunnable(threadGroup, r, threadsNumber++);
23 | }
24 |
25 | public ThreadContainer build() {
26 | return container;
27 | }
28 |
29 | }
30 |
31 | private final List list = new ArrayList<>();
32 | private boolean started;
33 |
34 | private ThreadContainer() {
35 | }
36 |
37 | void addRunnable(ThreadGroup g, Runnable r, int number) {
38 | list.add(new Thread(g, r, g.getName() + "-" + number));
39 | }
40 |
41 | public void startAsDaemon() {
42 | if (!started) {
43 | for (Thread t : list) {
44 | t.setDaemon(true);
45 | t.start();
46 | }
47 | started = true;
48 | }
49 | }
50 |
51 | public boolean isStarted() {
52 | return started;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Chapter07/garbage_sensor_alarm_figure_7_1_corrupted.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter07/garbage_sensor_alarm_figure_7_1_corrupted.jfr
--------------------------------------------------------------------------------
/Chapter07/garbage_sensor_alarm_figure_7_2_corected.jfr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/95db7dd0f84dcefb519addfe30eecff137a89b18/Chapter07/garbage_sensor_alarm_figure_7_2_corected.jfr
--------------------------------------------------------------------------------
/HowToCompileAndExecute.md:
--------------------------------------------------------------------------------
1 | ### How to compile a code
2 | ```bash
3 | $ javac --release 17 --enable-preview -g -cp out -sourcepath java -d out .///*.java
4 |
5 | # example
6 | $ javac --release 17 --enable-preview -g -cp out -sourcepath java -d out ./Chapter01/apie/*.java
7 |
8 | # create module jar
9 | $ jar --create --file module-example.jar -C out .
10 | ```
11 |
12 | ### How to execute example
13 | ```bash
14 | $ java --enable-preview -cp out/
15 |
16 | # example
17 | $ java --enable-preview -cp out/apie Example1_2Main
18 |
19 | # run module path
20 | $ java --module-path ./Chapter02/module-example.jar --module module.example/example.ExampleMain
21 | ```
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Practical Design Patterns for Java Developers
2 | [](LICENSE)
3 |
4 |
5 |
6 |
7 | This is the code repository for [ Practical Design Patterns for Java Developers ](https://www.packtpub.com/product/practical-design-patterns-for-java-developers/9781804614679), published by Packt.
8 |
9 | **Hone your software design skills by implementing popular design patterns in Java**
10 |
11 | ## What is this book about?
12 | As the experience level increases for software developers, it becomes crucial to develop the required skillset for developing quality code. This book will enable you to identify and apply common design patterns for building quality applications by refining your code.
13 |
14 | This book covers the following exciting features:
15 | * Understand the most common problems that can be solved using Java design patterns
16 | * Uncover Java building elements, their usages, and concurrency possibilities
17 | * Optimize a vehicle memory footprint with the Flyweight Pattern
18 | * Explore one-to-many relations between instances with the observer pattern
19 | * Discover how to route vehicle messages by using the visitor pattern
20 | * Utilize and control vehicle resources with the thread-pool pattern
21 | * Understand the penalties caused by anti-patterns in software design
22 |
23 | The book describes 42 popular design patterns formed into an imaginary abstraction of vehicle manufacturing to boost the learning curve (_Table 1._).
24 |
25 | | Creational | Structural | Behavioral | Concurrent |
26 | | :--- | :--- | :--- | :--- |
27 | | _Chapter 3_ | _Chapter 4_ | _Chapter 5_ | _Chapter 6_ |
28 | | Factory Method | Adapter | Caching | Active Object |
29 | | Abstract Factory | Bridge | Chain of Responsibility | Asynchronous Method |
30 | | Builder | Composite | Command | Balking |
31 | | Prototype | Decorator | Interpreter | Double Checked Locking |
32 | | Singleton | Facade | Iterator | Read Write Lock |
33 | | Object Pool | Filter | Mediator | Producer Consumer |
34 | | Lazy Initialization | Flyweight | Null Object | Scheduler |
35 | | Dependency Injection | Front Controller | Observer | Thread Pool |
36 | | | Marker | Pipeline | |
37 | | | Module | State | |
38 | | | Proxy | Strategy | |
39 | | | Twin | Template | |
40 | | | | Visitor | |
41 |
42 | _Table 1._ : **42** Practical Design Patterns explored in the book
43 |
44 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/180461467X) today!
45 | What led the author to write this book: [Miroslav Wengner: The Interview](https://authors.packtpub.com/interview-with-miroslav-wengner/)
46 |
47 |
49 |
50 |
51 |
52 | The book
53 |
54 | ## Instructions and Navigations
55 | All of the code is organized into folders. For example, Chapter02.
56 |
57 | The code will look like the following:
58 | ```
59 | public class Vehicle {
60 | private boolean moving;
61 | public void move(){
62 | this.moving = true;
63 | System.out.println("moving...");
64 | }
65 | ```
66 |
67 | **Following is what you need for this book:**
68 | If you are an intermediate-level Java developer or software architect looking to learn the practical implementation of software design patterns in Java, then this book is for you. No prior knowledge of design patterns is required, but an understanding of Java programming is necessary.
69 |
70 | With the following software and hardware list you can run all code files present in the book (Chapter 1-7).
71 | ### Software and Hardware List
72 | | Chapter | Software required | OS required |
73 | | -------- | ------------------------------------ | ----------------------------------- |
74 | | 1 | Java Development Kit 17+ | Windows, Mac OS X, and Linux (Any) |
75 | | 1 | Recommended IDE VSCode 1.73.1+ | Windows, Mac OS X, and Linux (Any) |
76 | | 1 | A text editor or IDE | Windows, Mac OS X, and Linux (Any) |
77 |
78 |
79 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it]( https://packt.link/nSLEf).
80 |
81 | ## Errata
82 | * Figure 2.1 The Extension class loader mentioned in the image should be the Application & Platform Classloader
83 | ### Related products
84 | * Domain-Driven Design with Java - A Practitioner’s Guide [[Packt]](https://www.packtpub.com/product/domain-driven-design-with-java-a-practitioners-guide/9781800560734?utm_source=github&utm_medium=repository&utm_campaign=) [[Amazon]](https://www.amazon.com/dp/1800560737)
85 |
86 | * Java Memory Management [[Packt]](https://www.packtpub.com/product/java-memory-management/9781801812856?utm_source=github&utm_medium=repository&utm_campaign=) [[Amazon]](https://www.amazon.com/dp/1801812853)
87 |
88 | ## How to install Java
89 | Java Development Kit 17+ is required to run the book's examples. To check if it is available on your system, execute the following commands:
90 | ```bash
91 | $ java -version
92 |
93 | # Expected output:
94 | openjdk version "17" 2021-09-14
95 | OpenJDK Runtime Environment (build 17+35-2724)
96 | OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode,
97 | sharing)
98 | ```
99 |
100 | In case the JDK is not installed, feel free to visit the following links for help:
101 | 1. [Foojay.io : Java Quick Start](https://foojay.io/java-quick-start/install-java/)
102 | 2. [dev.java : Getting Started with Java](https://dev.java/learn/)
103 | 3. [Homebrew Formulae: OpenJDK](https://formulae.brew.sh/formula/openjdk)
104 |
105 |
106 | ### How to create and open Java Flight Recorder recordings
107 | The project contains several ***.jfr** recordings. The file-name refers to the image that was created from this recording. **Java Mission Control version 8.2** was used for image creation purposes. *.jfr files can be opened in the **Java Mission Control application**, which can be downloaded from the links below.
108 |
109 | download links:
110 | - https://github.com/openjdk/jmc
111 | - https://adoptium.net/jmc/
112 |
113 | ```bash
114 | # Starting the JavaFlightRecorder for the patterns
115 | # Recordings are done on Java 17
116 | $ java -XX:StartFlightRecording=filename=.jfr,dumponexit=true,settings=profile
117 | ```
118 | [](https://github.com/PacktPublishing/Practical-Design-Patterns-for-Java-Developers/blob/main/HowToCompileAndExecute.md)
119 |
120 | ## Get to Know the Author
121 | **Miroslav Wengner**
122 | is an engineer with a passion for resilient distributed systems and product quality. He is a co-author and contributor to the Robo4J project (a reactive soft real-time framework for robotics/IoT). Miro contributes to OpenJDK and participates in other open source technologies. He uses his passion for helping build resilient and scalable solutions.
123 | Miro was selected for the Java Champions Program, recognized as a JavaOne Rockstar, and elected to the Java Community Process (JCP) as an executive committee member.He shares his knowledge at conferences (JavaOne, Devoxx, and so on) and in blogs. Miro believes in the Java ecosystem and helps move it forward!
124 |
125 | [](https://twitter.com/miragemiko)
126 | [](https://www.linkedin.com/in/mwengner/)
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | ### Download a free PDF
135 |
136 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
137 | https://packt.link/free-ebook/9781804614679
138 |
--------------------------------------------------------------------------------