diff --git a/observer/src/main/java/com/iluwatar/observer/App.java b/observer/src/main/java/com/iluwatar/observer/App.java index bc4742a14..5f03a9e2b 100644 --- a/observer/src/main/java/com/iluwatar/observer/App.java +++ b/observer/src/main/java/com/iluwatar/observer/App.java @@ -6,45 +6,44 @@ import com.iluwatar.observer.generic.GWeather; /** * - * The Observer pattern is a software design pattern in which an object, called - * the subject, maintains a list of its dependents, called observers, and notifies - * them automatically of any state changes, usually by calling one of their methods. - * It is mainly used to implement distributed event handling systems. The Observer - * pattern is also a key part in the familiar model–view–controller (MVC) architectural - * pattern. The Observer pattern is implemented in numerous programming libraries and - * systems, including almost all GUI toolkits. + * The Observer pattern is a software design pattern in which an object, called the subject, + * maintains a list of its dependents, called observers, and notifies them automatically of any + * state changes, usually by calling one of their methods. It is mainly used to implement + * distributed event handling systems. The Observer pattern is also a key part in the familiar + * model–view–controller (MVC) architectural pattern. The Observer pattern is implemented in + * numerous programming libraries and systems, including almost all GUI toolkits. *

- * In this example {@link Weather} has a state that can be observed. The {@link Orcs} - * and {@link Hobbits} register as observers and receive notifications when the - * {@link Weather} changes. + * In this example {@link Weather} has a state that can be observed. The {@link Orcs} and + * {@link Hobbits} register as observers and receive notifications when the {@link Weather} changes. * */ public class App { - /** - * Program entry point - * @param args command line args - */ - public static void main(String[] args) { + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { - Weather weather = new Weather(); - weather.addObserver(new Orcs()); - weather.addObserver(new Hobbits()); + Weather weather = new Weather(); + weather.addObserver(new Orcs()); + weather.addObserver(new Hobbits()); - weather.timePasses(); - weather.timePasses(); - weather.timePasses(); - weather.timePasses(); + weather.timePasses(); + weather.timePasses(); + weather.timePasses(); + weather.timePasses(); - // Generic observer inspired by Java Generics and Collection by Naftalin & Wadler - System.out.println("\n--Running generic version--"); - GWeather gWeather = new GWeather(); - gWeather.addObserver(new GOrcs()); - gWeather.addObserver(new GHobbits()); + // Generic observer inspired by Java Generics and Collection by Naftalin & Wadler + System.out.println("\n--Running generic version--"); + GWeather gWeather = new GWeather(); + gWeather.addObserver(new GOrcs()); + gWeather.addObserver(new GHobbits()); - gWeather.timePasses(); - gWeather.timePasses(); - gWeather.timePasses(); - gWeather.timePasses(); - } + gWeather.timePasses(); + gWeather.timePasses(); + gWeather.timePasses(); + gWeather.timePasses(); + } } diff --git a/observer/src/main/java/com/iluwatar/observer/Hobbits.java b/observer/src/main/java/com/iluwatar/observer/Hobbits.java index d15ce6109..02baaec83 100644 --- a/observer/src/main/java/com/iluwatar/observer/Hobbits.java +++ b/observer/src/main/java/com/iluwatar/observer/Hobbits.java @@ -7,24 +7,23 @@ package com.iluwatar.observer; */ public class Hobbits implements WeatherObserver { - @Override - public void update(WeatherType currentWeather) { - switch (currentWeather) { - case COLD: - System.out.println("The hobbits are shivering in the cold weather."); - break; - case RAINY: - System.out.println("The hobbits look for cover from the rain."); - break; - case SUNNY: - System.out.println("The happy hobbits bade in the warm sun."); - break; - case WINDY: - System.out.println("The hobbits hold their hats tightly in the windy weather."); - break; - default: - break; - } - } - + @Override + public void update(WeatherType currentWeather) { + switch (currentWeather) { + case COLD: + System.out.println("The hobbits are shivering in the cold weather."); + break; + case RAINY: + System.out.println("The hobbits look for cover from the rain."); + break; + case SUNNY: + System.out.println("The happy hobbits bade in the warm sun."); + break; + case WINDY: + System.out.println("The hobbits hold their hats tightly in the windy weather."); + break; + default: + break; + } + } } diff --git a/observer/src/main/java/com/iluwatar/observer/Orcs.java b/observer/src/main/java/com/iluwatar/observer/Orcs.java index 26049bf4b..09ca65211 100644 --- a/observer/src/main/java/com/iluwatar/observer/Orcs.java +++ b/observer/src/main/java/com/iluwatar/observer/Orcs.java @@ -7,24 +7,23 @@ package com.iluwatar.observer; */ public class Orcs implements WeatherObserver { - @Override - public void update(WeatherType currentWeather) { - switch (currentWeather) { - case COLD: - System.out.println("The orcs are freezing cold."); - break; - case RAINY: - System.out.println("The orcs are dripping wet."); - break; - case SUNNY: - System.out.println("The sun hurts the orcs' eyes."); - break; - case WINDY: - System.out.println("The orc smell almost vanishes in the wind."); - break; - default: - break; - } - } - + @Override + public void update(WeatherType currentWeather) { + switch (currentWeather) { + case COLD: + System.out.println("The orcs are freezing cold."); + break; + case RAINY: + System.out.println("The orcs are dripping wet."); + break; + case SUNNY: + System.out.println("The sun hurts the orcs' eyes."); + break; + case WINDY: + System.out.println("The orc smell almost vanishes in the wind."); + break; + default: + break; + } + } } diff --git a/observer/src/main/java/com/iluwatar/observer/Weather.java b/observer/src/main/java/com/iluwatar/observer/Weather.java index c5b03c7a3..634953945 100644 --- a/observer/src/main/java/com/iluwatar/observer/Weather.java +++ b/observer/src/main/java/com/iluwatar/observer/Weather.java @@ -5,38 +5,38 @@ import java.util.List; /** * - * Weather can be observed by implementing {@link WeatherObserver} interface and - * registering as listener. + * Weather can be observed by implementing {@link WeatherObserver} interface and registering as + * listener. * */ public class Weather { - private WeatherType currentWeather; - private List observers; + private WeatherType currentWeather; + private List observers; - public Weather() { - observers = new ArrayList<>(); - currentWeather = WeatherType.SUNNY; - } + public Weather() { + observers = new ArrayList<>(); + currentWeather = WeatherType.SUNNY; + } - public void addObserver(WeatherObserver obs) { - observers.add(obs); - } + public void addObserver(WeatherObserver obs) { + observers.add(obs); + } - public void removeObserver(WeatherObserver obs) { - observers.remove(obs); - } + public void removeObserver(WeatherObserver obs) { + observers.remove(obs); + } - public void timePasses() { - WeatherType[] enumValues = WeatherType.values(); - currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; - System.out.println("The weather changed to " + currentWeather + "."); - notifyObservers(); - } + public void timePasses() { + WeatherType[] enumValues = WeatherType.values(); + currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; + System.out.println("The weather changed to " + currentWeather + "."); + notifyObservers(); + } - private void notifyObservers() { - for (WeatherObserver obs : observers) { - obs.update(currentWeather); - } - } + private void notifyObservers() { + for (WeatherObserver obs : observers) { + obs.update(currentWeather); + } + } } diff --git a/observer/src/main/java/com/iluwatar/observer/WeatherObserver.java b/observer/src/main/java/com/iluwatar/observer/WeatherObserver.java index 5491da75e..1293214cd 100644 --- a/observer/src/main/java/com/iluwatar/observer/WeatherObserver.java +++ b/observer/src/main/java/com/iluwatar/observer/WeatherObserver.java @@ -7,6 +7,6 @@ package com.iluwatar.observer; */ public interface WeatherObserver { - void update(WeatherType currentWeather); + void update(WeatherType currentWeather); } diff --git a/observer/src/main/java/com/iluwatar/observer/WeatherType.java b/observer/src/main/java/com/iluwatar/observer/WeatherType.java index 173a53205..c808368cf 100644 --- a/observer/src/main/java/com/iluwatar/observer/WeatherType.java +++ b/observer/src/main/java/com/iluwatar/observer/WeatherType.java @@ -7,11 +7,10 @@ package com.iluwatar.observer; */ public enum WeatherType { - SUNNY, RAINY, WINDY, COLD; - - @Override - public String toString() { - return this.name().toLowerCase(); - } + SUNNY, RAINY, WINDY, COLD; + @Override + public String toString() { + return this.name().toLowerCase(); + } } diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java b/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java index ec19d68e1..5dca0e779 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java @@ -8,23 +8,23 @@ import com.iluwatar.observer.WeatherType; * */ public class GHobbits implements Race { - @Override - public void update(GWeather weather, WeatherType weatherType) { - switch (weatherType) { - case COLD: - System.out.println("The hobbits are shivering in the cold weather."); - break; - case RAINY: - System.out.println("The hobbits look for cover from the rain."); - break; - case SUNNY: - System.out.println("The happy hobbits bade in the warm sun."); - break; - case WINDY: - System.out.println("The hobbits hold their hats tightly in the windy weather."); - break; - default: - break; - } + @Override + public void update(GWeather weather, WeatherType weatherType) { + switch (weatherType) { + case COLD: + System.out.println("The hobbits are shivering in the cold weather."); + break; + case RAINY: + System.out.println("The hobbits look for cover from the rain."); + break; + case SUNNY: + System.out.println("The happy hobbits bade in the warm sun."); + break; + case WINDY: + System.out.println("The hobbits hold their hats tightly in the windy weather."); + break; + default: + break; } + } } diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java b/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java index 037b88a1d..b279a78c1 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java @@ -8,24 +8,24 @@ import com.iluwatar.observer.WeatherType; * */ public class GOrcs implements Race { - - @Override - public void update(GWeather weather, WeatherType weatherType) { - switch (weatherType) { - case COLD: - System.out.println("The orcs are freezing cold."); - break; - case RAINY: - System.out.println("The orcs are dripping wet."); - break; - case SUNNY: - System.out.println("The sun hurts the orcs' eyes."); - break; - case WINDY: - System.out.println("The orc smell almost vanishes in the wind."); - break; - default: - break; - } + + @Override + public void update(GWeather weather, WeatherType weatherType) { + switch (weatherType) { + case COLD: + System.out.println("The orcs are freezing cold."); + break; + case RAINY: + System.out.println("The orcs are dripping wet."); + break; + case SUNNY: + System.out.println("The sun hurts the orcs' eyes."); + break; + case WINDY: + System.out.println("The orc smell almost vanishes in the wind."); + break; + default: + break; } + } } diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java b/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java index cea86bc82..9d1c6ed07 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java @@ -9,16 +9,16 @@ import com.iluwatar.observer.WeatherType; */ public class GWeather extends Observable { - private WeatherType currentWeather; + private WeatherType currentWeather; - public GWeather() { - currentWeather = WeatherType.SUNNY; - } + public GWeather() { + currentWeather = WeatherType.SUNNY; + } - public void timePasses() { - WeatherType[] enumValues = WeatherType.values(); - currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; - System.out.println("The weather changed to " + currentWeather + "."); - notifyObservers(currentWeather); - } + public void timePasses() { + WeatherType[] enumValues = WeatherType.values(); + currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; + System.out.println("The weather changed to " + currentWeather + "."); + notifyObservers(currentWeather); + } } diff --git a/observer/src/main/java/com/iluwatar/observer/generic/Observable.java b/observer/src/main/java/com/iluwatar/observer/generic/Observable.java index eaedc7b6e..f1ad2dca6 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/Observable.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/Observable.java @@ -12,20 +12,20 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public abstract class Observable, O extends Observer, A> { - protected List observers; + protected List observers; - public Observable() { - this.observers = new CopyOnWriteArrayList<>(); - } + public Observable() { + this.observers = new CopyOnWriteArrayList<>(); + } - public void addObserver(O observer) { - this.observers.add(observer); - } + public void addObserver(O observer) { + this.observers.add(observer); + } - @SuppressWarnings("unchecked") - public void notifyObservers(A argument) { - for (O observer : observers) { - observer.update((S) this, argument); - } + @SuppressWarnings("unchecked") + public void notifyObservers(A argument) { + for (O observer : observers) { + observer.update((S) this, argument); } + } } diff --git a/observer/src/main/java/com/iluwatar/observer/generic/Observer.java b/observer/src/main/java/com/iluwatar/observer/generic/Observer.java index 2338f9e98..b01955419 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/Observer.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/Observer.java @@ -10,5 +10,5 @@ package com.iluwatar.observer.generic; */ public interface Observer, O extends Observer, A> { - void update(S subject, A argument); + void update(S subject, A argument); } diff --git a/observer/src/test/java/com/iluwatar/observer/AppTest.java b/observer/src/test/java/com/iluwatar/observer/AppTest.java index 38d5c0503..65976626d 100644 --- a/observer/src/test/java/com/iluwatar/observer/AppTest.java +++ b/observer/src/test/java/com/iluwatar/observer/AppTest.java @@ -11,9 +11,9 @@ import com.iluwatar.observer.App; */ public class AppTest { - @Test - public void test() { - String[] args = {}; - App.main(args); - } + @Test + public void test() { + String[] args = {}; + App.main(args); + } } diff --git a/pom.xml b/pom.xml index 36e43727b..3462cc864 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ execute-around property intercepting-filter + producer-consumer poison-pill lazy-loading service-layer diff --git a/producer-consumer/etc/producer-consumer.png b/producer-consumer/etc/producer-consumer.png new file mode 100644 index 000000000..e8bc573b3 Binary files /dev/null and b/producer-consumer/etc/producer-consumer.png differ diff --git a/producer-consumer/etc/producer-consumer.ucls b/producer-consumer/etc/producer-consumer.ucls new file mode 100644 index 000000000..aa1ee80c0 --- /dev/null +++ b/producer-consumer/etc/producer-consumer.ucls @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/producer-consumer/index.md b/producer-consumer/index.md new file mode 100644 index 000000000..58dc45e0d --- /dev/null +++ b/producer-consumer/index.md @@ -0,0 +1,22 @@ +--- +layout: pattern +title: Producer Consumer +folder: producer-consumer +permalink: /patterns/producer-consumer/ +categories: Other +tags: Java +--- + +**Intent:** Producer Consumer Design pattern is a classic concurrency or threading pattern which reduces + coupling between Producer and Consumer by separating Identification of work with Execution of + Work.. + + + +![alt text](./etc/producer-consumer.png "Producer Consumer") + +**Applicability:** Use the Producer Consumer idiom when + +* decouple system by separate work in two process produce and consume. +* addresses the issue of different timing require to produce work or consuming work + diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml new file mode 100644 index 000000000..475c7fb6c --- /dev/null +++ b/producer-consumer/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.7.0 + + producer-consumer + + + junit + junit + test + + + diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java new file mode 100644 index 000000000..50d94d92f --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java @@ -0,0 +1,57 @@ +package com.iluwatar.producer.consumer; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Producer Consumer Design pattern is a classic concurrency or threading pattern which reduces + * coupling between Producer and Consumer by separating Identification of work with Execution of + * Work. + *

+ * In producer consumer design pattern a shared queue is used to control the flow and this + * separation allows you to code producer and consumer separately. It also addresses the issue of + * different timing require to produce item or consuming item. by using producer consumer pattern + * both Producer and Consumer Thread can work with different speed. + * + */ +public class App { + + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { + + ItemQueue queue = new ItemQueue(); + + ExecutorService executorService = Executors.newFixedThreadPool(5); + for (int i = 0; i < 2; i++) { + + final Producer producer = new Producer("Producer_" + i, queue); + executorService.submit(() -> { + while (true) { + producer.produce(); + } + }); + }; + + for (int i = 0; i < 3; i++) { + final Consumer consumer = new Consumer("Consumer_" + i, queue); + executorService.submit(() -> { + while (true) { + consumer.consume(); + } + }); + } + + executorService.shutdown(); + try { + executorService.awaitTermination(10, TimeUnit.SECONDS); + executorService.shutdownNow(); + } catch (InterruptedException e) { + System.out.println("Error waiting for ExecutorService shutdown"); + } + } +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java new file mode 100644 index 000000000..8bb3b75b6 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java @@ -0,0 +1,24 @@ +package com.iluwatar.producer.consumer; + +/** + * Class responsible for consume the {@link Item} produced by {@link Producer} + */ +public class Consumer { + + private final ItemQueue queue; + + private final String name; + + public Consumer(String name, ItemQueue queue) { + this.name = name; + this.queue = queue; + } + + public void consume() throws InterruptedException { + + Item item = queue.take(); + System.out.println(String.format("Consumer [%s] consume item [%s] produced by [%s]", name, + item.getId(), item.getProducer())); + + } +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java new file mode 100644 index 000000000..8d5be69a1 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java @@ -0,0 +1,27 @@ +package com.iluwatar.producer.consumer; + +/** + * Class take part of an {@link Producer}-{@link Consumer} exchange. + */ +public class Item { + + private String producer; + + private int id; + + public Item(String producer, int id) { + this.id = id; + this.producer = producer; + } + + public int getId() { + + return id; + } + + public String getProducer() { + + return producer; + } + +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java new file mode 100644 index 000000000..8d41fb456 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java @@ -0,0 +1,27 @@ +package com.iluwatar.producer.consumer; + +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Class as a channel for {@link Producer}-{@link Consumer} exchange. + */ +public class ItemQueue { + + private LinkedBlockingQueue queue; + + public ItemQueue() { + + queue = new LinkedBlockingQueue(5); + } + + public void put(Item item) throws InterruptedException { + + queue.put(item); + } + + public Item take() throws InterruptedException { + + return queue.take(); + } + +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java new file mode 100644 index 000000000..40e71c607 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java @@ -0,0 +1,29 @@ +package com.iluwatar.producer.consumer; + +import java.util.Random; + +/** + * Class responsible for producing unit of work that can be expressed as {@link Item} and submitted + * to queue + */ +public class Producer { + + private final ItemQueue queue; + + private final String name; + + private int itemId = 0; + + public Producer(String name, ItemQueue queue) { + this.name = name; + this.queue = queue; + } + + public void produce() throws InterruptedException { + + Item item = new Item(name, itemId++); + queue.put(item); + Random random = new Random(); + Thread.sleep(random.nextInt(2000)); + } +} diff --git a/producer-consumer/src/test/java/com/iluwatar/poison/pill/AppTest.java b/producer-consumer/src/test/java/com/iluwatar/poison/pill/AppTest.java new file mode 100644 index 000000000..26b38dec0 --- /dev/null +++ b/producer-consumer/src/test/java/com/iluwatar/poison/pill/AppTest.java @@ -0,0 +1,20 @@ +package com.iluwatar.poison.pill; + +import org.junit.Test; + +import com.iluwatar.producer.consumer.App; + +/** + * + * Application test + * + */ +public class AppTest { + + @Test + public void test() throws Exception { + String[] args = {}; + App.main(args); + + } +}