Reformat rest of the design patterns - Issue #224

This commit is contained in:
Ankur Kaushal 2015-11-01 21:29:13 -05:00
parent 449340bd2b
commit 306b1f3d31
337 changed files with 6744 additions and 6851 deletions

View File

@ -6,38 +6,37 @@ import java.util.concurrent.TimeUnit;
/** /**
* *
* Double Checked Locking is a concurrency design pattern used to reduce the overhead * Double Checked Locking is a concurrency design pattern used to reduce the overhead of acquiring a
* of acquiring a lock by first testing the locking criterion (the "lock hint") without * lock by first testing the locking criterion (the "lock hint") without actually acquiring the
* actually acquiring the lock. Only if the locking criterion check indicates that * lock. Only if the locking criterion check indicates that locking is required does the actual
* locking is required does the actual locking logic proceed. * locking logic proceed.
* <p> * <p>
* In {@link Inventory} we store the items with a given size. However, we do not store * In {@link Inventory} we store the items with a given size. However, we do not store more items
* more items than the inventory size. To address concurrent access problems we * than the inventory size. To address concurrent access problems we use double checked locking to
* use double checked locking to add item to inventory. In this method, the * add item to inventory. In this method, the thread which gets the lock first adds the item.
* thread which gets the lock first adds the item.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
final Inventory inventory = new Inventory(1000); public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3); final Inventory inventory = new Inventory(1000);
for (int i = 0; i < 3; i++) { ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.execute(() -> { for (int i = 0; i < 3; i++) {
while (inventory.addItem(new Item())) executorService.execute(() -> {
; while (inventory.addItem(new Item()));
}); });
} }
executorService.shutdown(); executorService.shutdown();
try { try {
executorService.awaitTermination(5, TimeUnit.SECONDS); executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("Error waiting for ExecutorService shutdown"); System.out.println("Error waiting for ExecutorService shutdown");
} }
} }
} }

View File

@ -12,32 +12,30 @@ import java.util.concurrent.locks.ReentrantLock;
*/ */
public class Inventory { public class Inventory {
private final int inventorySize; private final int inventorySize;
private final List<Item> items; private final List<Item> items;
private final Lock lock; private final Lock lock;
public Inventory(int inventorySize) { public Inventory(int inventorySize) {
this.inventorySize = inventorySize; this.inventorySize = inventorySize;
this.items = new ArrayList<>(inventorySize); this.items = new ArrayList<>(inventorySize);
this.lock = new ReentrantLock(); this.lock = new ReentrantLock();
} }
public boolean addItem(Item item) {
if (items.size() < inventorySize) {
lock.lock();
try {
if (items.size() < inventorySize) {
items.add(item);
System.out.println(Thread.currentThread()
+ ": items.size()=" + items.size()
+ ", inventorySize=" + inventorySize);
return true;
}
} finally {
lock.unlock();
}
}
return false;
}
public boolean addItem(Item item) {
if (items.size() < inventorySize) {
lock.lock();
try {
if (items.size() < inventorySize) {
items.add(item);
System.out.println(Thread.currentThread() + ": items.size()=" + items.size()
+ ", inventorySize=" + inventorySize);
return true;
}
} finally {
lock.unlock();
}
}
return false;
}
} }

View File

@ -6,7 +6,7 @@ package com.iluwatar.doublechecked.locking;
* *
*/ */
public class Item { public class Item {
private String name; private String name;
private int level; private int level;
} }

View File

@ -11,9 +11,9 @@ import com.iluwatar.doublechecked.locking.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -5,46 +5,50 @@ import java.util.List;
/** /**
* *
* When a message with a parameter is sent to an object, the resultant behaviour is defined by the * When a message with a parameter is sent to an object, the resultant behaviour is defined by the
* implementation of that method in the receiver. Sometimes the behaviour must also be determined * implementation of that method in the receiver. Sometimes the behaviour must also be determined by
* by the type of the parameter. * the type of the parameter.
* <p> * <p>
* One way to implement this would be to create multiple instanceof-checks for the methods parameter. * One way to implement this would be to create multiple instanceof-checks for the methods
* However, this creates a maintenance issue. When new types are added we would also need to change * parameter. However, this creates a maintenance issue. When new types are added we would also need
* the method's implementation and add a new instanceof-check. This violates the single responsibility * to change the method's implementation and add a new instanceof-check. This violates the single
* principle - a class should have only one reason to change. * responsibility principle - a class should have only one reason to change.
* <p> * <p>
* Instead of the instanceof-checks a better way is to make another virtual call on the parameter * Instead of the instanceof-checks a better way is to make another virtual call on the parameter
* object. This way new functionality can be easily added without the need to modify existing * object. This way new functionality can be easily added without the need to modify existing
* implementation (open-closed principle). * implementation (open-closed principle).
* <p> * <p>
* In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other. Each * In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other.
* object has its own coordinates which are checked against the other objects' coordinates. If * Each object has its own coordinates which are checked against the other objects' coordinates. If
* there is an overlap, then the objects collide utilizing the Double Dispatch pattern. * there is an overlap, then the objects collide utilizing the Double Dispatch pattern.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main( String[] args ) { */
// initialize game objects and print their status public static void main(String[] args) {
List<GameObject> objects = new ArrayList<>(); // initialize game objects and print their status
objects.add(new FlamingAsteroid(0, 0, 5, 5)); List<GameObject> objects = new ArrayList<>();
objects.add(new SpaceStationMir(1, 1, 2, 2)); objects.add(new FlamingAsteroid(0, 0, 5, 5));
objects.add(new Meteoroid(10, 10, 15, 15)); objects.add(new SpaceStationMir(1, 1, 2, 2));
objects.add(new SpaceStationIss(12, 12, 14, 14)); objects.add(new Meteoroid(10, 10, 15, 15));
objects.stream().forEach(o -> System.out.println(o)); objects.add(new SpaceStationIss(12, 12, 14, 14));
System.out.println(""); objects.stream().forEach(o -> System.out.println(o));
System.out.println("");
// collision check
objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> { if (o1 != o2 && o1.intersectsWith(o2)) o1.collision(o2); } )); // collision check
System.out.println(""); objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> {
if (o1 != o2 && o1.intersectsWith(o2))
// output eventual object statuses o1.collision(o2);
objects.stream().forEach(o -> System.out.println(o)); }));
System.out.println(""); System.out.println("");
}
// output eventual object statuses
objects.stream().forEach(o -> System.out.println(o));
System.out.println("");
}
} }

View File

@ -7,13 +7,13 @@ package com.iluwatar.doubledispatch;
*/ */
public class FlamingAsteroid extends Meteoroid { public class FlamingAsteroid extends Meteoroid {
public FlamingAsteroid(int left, int top, int right, int bottom) { public FlamingAsteroid(int left, int top, int right, int bottom) {
super(left, top, right, bottom); super(left, top, right, bottom);
setOnFire(true); setOnFire(true);
} }
@Override @Override
public void collision(GameObject gameObject) { public void collision(GameObject gameObject) {
gameObject.collisionResolve(this); gameObject.collisionResolve(this);
} }
} }

View File

@ -2,48 +2,47 @@ package com.iluwatar.doubledispatch;
/** /**
* *
* Game objects have coordinates and some * Game objects have coordinates and some other status information.
* other status information.
* *
*/ */
public abstract class GameObject extends Rectangle { public abstract class GameObject extends Rectangle {
private boolean damaged;
private boolean onFire;
public GameObject(int left, int top, int right, int bottom) {
super(left, top, right, bottom);
}
@Override
public String toString() {
return String.format("%s at %s damaged=%b onFire=%b", this.getClass().getSimpleName(),
super.toString(), isDamaged(), isOnFire());
}
public boolean isOnFire() {
return onFire;
}
public void setOnFire(boolean onFire) {
this.onFire = onFire;
}
public boolean isDamaged() {
return damaged;
}
public void setDamaged(boolean damaged) {
this.damaged = damaged;
}
public abstract void collision(GameObject gameObject);
public abstract void collisionResolve(FlamingAsteroid asteroid);
public abstract void collisionResolve(Meteoroid meteoroid); private boolean damaged;
private boolean onFire;
public abstract void collisionResolve(SpaceStationMir mir); public GameObject(int left, int top, int right, int bottom) {
super(left, top, right, bottom);
}
public abstract void collisionResolve(SpaceStationIss iss); @Override
public String toString() {
return String.format("%s at %s damaged=%b onFire=%b", this.getClass().getSimpleName(),
super.toString(), isDamaged(), isOnFire());
}
public boolean isOnFire() {
return onFire;
}
public void setOnFire(boolean onFire) {
this.onFire = onFire;
}
public boolean isDamaged() {
return damaged;
}
public void setDamaged(boolean damaged) {
this.damaged = damaged;
}
public abstract void collision(GameObject gameObject);
public abstract void collisionResolve(FlamingAsteroid asteroid);
public abstract void collisionResolve(Meteoroid meteoroid);
public abstract void collisionResolve(SpaceStationMir mir);
public abstract void collisionResolve(SpaceStationIss iss);
} }

View File

@ -7,32 +7,36 @@ package com.iluwatar.doubledispatch;
*/ */
public class Meteoroid extends GameObject { public class Meteoroid extends GameObject {
public Meteoroid(int left, int top, int right, int bottom) { public Meteoroid(int left, int top, int right, int bottom) {
super(left, top, right, bottom); super(left, top, right, bottom);
} }
@Override @Override
public void collision(GameObject gameObject) { public void collision(GameObject gameObject) {
gameObject.collisionResolve(this); gameObject.collisionResolve(this);
} }
@Override @Override
public void collisionResolve(FlamingAsteroid asteroid) { public void collisionResolve(FlamingAsteroid asteroid) {
System.out.println(String.format("%s hits %s.", asteroid.getClass().getSimpleName(), this.getClass().getSimpleName())); System.out.println(String.format("%s hits %s.", asteroid.getClass().getSimpleName(), this
} .getClass().getSimpleName()));
}
@Override @Override
public void collisionResolve(Meteoroid meteoroid) { public void collisionResolve(Meteoroid meteoroid) {
System.out.println(String.format("%s hits %s.", meteoroid.getClass().getSimpleName(), this.getClass().getSimpleName())); System.out.println(String.format("%s hits %s.", meteoroid.getClass().getSimpleName(), this
} .getClass().getSimpleName()));
}
@Override @Override
public void collisionResolve(SpaceStationMir mir) { public void collisionResolve(SpaceStationMir mir) {
System.out.println(String.format("%s hits %s.", mir.getClass().getSimpleName(), this.getClass().getSimpleName())); System.out.println(String.format("%s hits %s.", mir.getClass().getSimpleName(), this.getClass()
} .getSimpleName()));
}
@Override @Override
public void collisionResolve(SpaceStationIss iss) { public void collisionResolve(SpaceStationIss iss) {
System.out.println(String.format("%s hits %s.", iss.getClass().getSimpleName(), this.getClass().getSimpleName())); System.out.println(String.format("%s hits %s.", iss.getClass().getSimpleName(), this.getClass()
} .getSimpleName()));
}
} }

View File

@ -2,43 +2,46 @@ package com.iluwatar.doubledispatch;
/** /**
* *
* Rectangle has coordinates and can be checked for overlap against * Rectangle has coordinates and can be checked for overlap against other Rectangles.
* other Rectangles.
* *
*/ */
public class Rectangle { public class Rectangle {
private int left; private int left;
private int top; private int top;
private int right; private int right;
private int bottom; private int bottom;
public Rectangle(int left, int top, int right, int bottom) { public Rectangle(int left, int top, int right, int bottom) {
this.left = left; this.left = left;
this.top = top; this.top = top;
this.right = right; this.right = right;
this.bottom = bottom; this.bottom = bottom;
} }
public int getLeft() { public int getLeft() {
return left; return left;
} }
public int getTop() {
return top; public int getTop() {
} return top;
public int getRight() { }
return right;
} public int getRight() {
public int getBottom() { return right;
return bottom; }
}
public int getBottom() {
boolean intersectsWith(Rectangle r) { return bottom;
return !(r.getLeft() > getRight() || r.getRight() < getLeft() || r.getTop() > getBottom() || r.getBottom() < getTop()); }
}
boolean intersectsWith(Rectangle r) {
@Override return !(r.getLeft() > getRight() || r.getRight() < getLeft() || r.getTop() > getBottom() || r
public String toString() { .getBottom() < getTop());
return String.format("[%d,%d,%d,%d]", getLeft(), getTop(), getRight(), getBottom()); }
}
@Override
public String toString() {
return String.format("[%d,%d,%d,%d]", getLeft(), getTop(), getRight(), getBottom());
}
} }

View File

@ -7,12 +7,12 @@ package com.iluwatar.doubledispatch;
*/ */
public class SpaceStationIss extends SpaceStationMir { public class SpaceStationIss extends SpaceStationMir {
public SpaceStationIss(int left, int top, int right, int bottom) { public SpaceStationIss(int left, int top, int right, int bottom) {
super(left, top, right, bottom); super(left, top, right, bottom);
} }
@Override @Override
public void collision(GameObject gameObject) { public void collision(GameObject gameObject) {
gameObject.collisionResolve(this); gameObject.collisionResolve(this);
} }
} }

View File

@ -7,45 +7,42 @@ package com.iluwatar.doubledispatch;
*/ */
public class SpaceStationMir extends GameObject { public class SpaceStationMir extends GameObject {
public SpaceStationMir(int left, int top, int right, int bottom) { public SpaceStationMir(int left, int top, int right, int bottom) {
super(left, top, right, bottom); super(left, top, right, bottom);
} }
@Override @Override
public void collision(GameObject gameObject) { public void collision(GameObject gameObject) {
gameObject.collisionResolve(this); gameObject.collisionResolve(this);
} }
@Override @Override
public void collisionResolve(FlamingAsteroid asteroid) { public void collisionResolve(FlamingAsteroid asteroid) {
System.out.println(String.format("%s hits %s. %s is damaged! %s is set on fire!", System.out.println(String.format("%s hits %s. %s is damaged! %s is set on fire!", asteroid
asteroid.getClass().getSimpleName(), this.getClass().getSimpleName(), .getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass()
this.getClass().getSimpleName(), this.getClass().getSimpleName())); .getSimpleName(), this.getClass().getSimpleName()));
setDamaged(true); setDamaged(true);
setOnFire(true); setOnFire(true);
} }
@Override @Override
public void collisionResolve(Meteoroid meteoroid) { public void collisionResolve(Meteoroid meteoroid) {
System.out.println(String.format("%s hits %s. %s is damaged!", System.out.println(String.format("%s hits %s. %s is damaged!", meteoroid.getClass()
meteoroid.getClass().getSimpleName(), this.getClass().getSimpleName(), .getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName()));
this.getClass().getSimpleName())); setDamaged(true);
setDamaged(true); }
}
@Override @Override
public void collisionResolve(SpaceStationMir mir) { public void collisionResolve(SpaceStationMir mir) {
System.out.println(String.format("%s hits %s. %s is damaged!", System.out.println(String.format("%s hits %s. %s is damaged!", mir.getClass().getSimpleName(),
mir.getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName()));
this.getClass().getSimpleName())); setDamaged(true);
setDamaged(true); }
}
@Override @Override
public void collisionResolve(SpaceStationIss iss) { public void collisionResolve(SpaceStationIss iss) {
System.out.println(String.format("%s hits %s. %s is damaged!", System.out.println(String.format("%s hits %s. %s is damaged!", iss.getClass().getSimpleName(),
iss.getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName()));
this.getClass().getSimpleName())); setDamaged(true);
setDamaged(true); }
}
} }

View File

@ -10,10 +10,10 @@ import com.iluwatar.doubledispatch.App;
* *
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -12,11 +12,11 @@ import com.iluwatar.doubledispatch.Rectangle;
*/ */
public class RectangleTest { public class RectangleTest {
@Test @Test
public void test() { public void test() {
Assert.assertTrue(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(0,0,1,1))); Assert.assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(0, 0, 1, 1)));
Assert.assertTrue(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(-1,-5,7,8))); Assert.assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-1, -5, 7, 8)));
Assert.assertFalse(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(2,2,3,3))); Assert.assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(2, 2, 3, 3)));
Assert.assertFalse(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(-2,-2,-1,-1))); Assert.assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-2, -2, -1, -1)));
} }
} }

View File

@ -5,39 +5,40 @@ import java.util.List;
/** /**
* *
* A system with lots of objects can lead to complexities when a client wants to subscribe * A system with lots of objects can lead to complexities when a client wants to subscribe to
* to events. The client has to find and register for each object individually, if each * events. The client has to find and register for each object individually, if each object has
* object has multiple events then each event requires a separate subscription. * multiple events then each event requires a separate subscription.
* <p> * <p>
* An Event Aggregator acts as a single source of events for many objects. It registers * An Event Aggregator acts as a single source of events for many objects. It registers for all the
* for all the events of the many objects allowing clients to register with just the aggregator. * events of the many objects allowing clients to register with just the aggregator.
* <p> * <p>
* In the example {@link LordBaelish}, {@link LordVarys} and {@link Scout} deliver events to * In the example {@link LordBaelish}, {@link LordVarys} and {@link Scout} deliver events to
* {@link KingsHand}. {@link KingsHand}, the event aggregator, then delivers the events * {@link KingsHand}. {@link KingsHand}, the event aggregator, then delivers the events to
* to {@link KingJoffrey}. * {@link KingJoffrey}.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
public static void main(String[] args) {
KingJoffrey kingJoffrey = new KingJoffrey();
KingsHand kingsHand = new KingsHand(kingJoffrey);
List<EventEmitter> emitters = new ArrayList<>(); KingJoffrey kingJoffrey = new KingJoffrey();
emitters.add(kingsHand); KingsHand kingsHand = new KingsHand(kingJoffrey);
emitters.add(new LordBaelish(kingsHand));
emitters.add(new LordVarys(kingsHand)); List<EventEmitter> emitters = new ArrayList<>();
emitters.add(new Scout(kingsHand)); emitters.add(kingsHand);
emitters.add(new LordBaelish(kingsHand));
for (Weekday day: Weekday.values()) { emitters.add(new LordVarys(kingsHand));
for (EventEmitter emitter: emitters) { emitters.add(new Scout(kingsHand));
emitter.timePasses(day);
} for (Weekday day : Weekday.values()) {
} for (EventEmitter emitter : emitters) {
} emitter.timePasses(day);
}
}
}
} }

View File

@ -7,15 +7,16 @@ package com.iluwatar.event.aggregator;
*/ */
public enum Event { public enum Event {
STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED("Traitor detected"); STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED(
"Traitor detected");
private String description;
private String description;
Event(String description) {
this.description = description; Event(String description) {
} this.description = description;
}
public String toString() {
return description; public String toString() {
} return description;
}
} }

View File

@ -10,26 +10,26 @@ import java.util.List;
*/ */
public abstract class EventEmitter { public abstract class EventEmitter {
private List<EventObserver> observers; private List<EventObserver> observers;
public EventEmitter() { public EventEmitter() {
observers = new LinkedList<>(); observers = new LinkedList<>();
} }
public EventEmitter(EventObserver obs) { public EventEmitter(EventObserver obs) {
this(); this();
registerObserver(obs); registerObserver(obs);
} }
public void registerObserver(EventObserver obs) { public void registerObserver(EventObserver obs) {
observers.add(obs); observers.add(obs);
} }
protected void notifyObservers(Event e) { protected void notifyObservers(Event e) {
for (EventObserver obs: observers) { for (EventObserver obs : observers) {
obs.onEvent(e); obs.onEvent(e);
} }
} }
public abstract void timePasses(Weekday day); public abstract void timePasses(Weekday day);
} }

View File

@ -6,7 +6,7 @@ package com.iluwatar.event.aggregator;
* *
*/ */
public interface EventObserver { public interface EventObserver {
void onEvent(Event e); void onEvent(Event e);
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.event.aggregator;
*/ */
public class KingJoffrey implements EventObserver { public class KingJoffrey implements EventObserver {
@Override @Override
public void onEvent(Event e) { public void onEvent(Event e) {
System.out.println("Received event from the King's Hand: " + e.toString()); System.out.println("Received event from the King's Hand: " + e.toString());
} }
} }

View File

@ -2,27 +2,26 @@ package com.iluwatar.event.aggregator;
/** /**
* *
* KingsHand observes events from multiple sources and delivers them * KingsHand observes events from multiple sources and delivers them to listeners.
* to listeners.
* *
*/ */
public class KingsHand extends EventEmitter implements EventObserver { public class KingsHand extends EventEmitter implements EventObserver {
public KingsHand() { public KingsHand() {
super(); super();
} }
public KingsHand(EventObserver obs) { public KingsHand(EventObserver obs) {
super(obs); super(obs);
} }
@Override
public void onEvent(Event e) {
notifyObservers(e);
}
@Override @Override
public void timePasses(Weekday day) { public void onEvent(Event e) {
// NOP notifyObservers(e);
} }
@Override
public void timePasses(Weekday day) {
// NOP
}
} }

View File

@ -6,19 +6,19 @@ package com.iluwatar.event.aggregator;
* *
*/ */
public class LordBaelish extends EventEmitter { public class LordBaelish extends EventEmitter {
public LordBaelish() {
super();
}
public LordBaelish(EventObserver obs) { public LordBaelish() {
super(obs); super();
} }
@Override public LordBaelish(EventObserver obs) {
public void timePasses(Weekday day) { super(obs);
if (day.equals(Weekday.FRIDAY)) { }
notifyObservers(Event.STARK_SIGHTED);
} @Override
} public void timePasses(Weekday day) {
if (day.equals(Weekday.FRIDAY)) {
notifyObservers(Event.STARK_SIGHTED);
}
}
} }

View File

@ -6,19 +6,19 @@ package com.iluwatar.event.aggregator;
* *
*/ */
public class LordVarys extends EventEmitter { public class LordVarys extends EventEmitter {
public LordVarys() {
super();
}
public LordVarys(EventObserver obs) { public LordVarys() {
super(obs); super();
} }
@Override public LordVarys(EventObserver obs) {
public void timePasses(Weekday day) { super(obs);
if (day.equals(Weekday.SATURDAY)) { }
notifyObservers(Event.TRAITOR_DETECTED);
} @Override
} public void timePasses(Weekday day) {
if (day.equals(Weekday.SATURDAY)) {
notifyObservers(Event.TRAITOR_DETECTED);
}
}
} }

View File

@ -6,19 +6,19 @@ package com.iluwatar.event.aggregator;
* *
*/ */
public class Scout extends EventEmitter { public class Scout extends EventEmitter {
public Scout() {
super();
}
public Scout(EventObserver obs) { public Scout() {
super(obs); super();
} }
@Override public Scout(EventObserver obs) {
public void timePasses(Weekday day) { super(obs);
if (day.equals(Weekday.TUESDAY)) { }
notifyObservers(Event.WARSHIPS_APPROACHING);
} @Override
} public void timePasses(Weekday day) {
if (day.equals(Weekday.TUESDAY)) {
notifyObservers(Event.WARSHIPS_APPROACHING);
}
}
} }

View File

@ -6,16 +6,17 @@ package com.iluwatar.event.aggregator;
* *
*/ */
public enum Weekday { public enum Weekday {
MONDAY("Monday"), TUESDAY("Tuesday"), WEDNESDAY("Wednesday"), THURSDAY("Thursday"), FRIDAY("Friday"), SATURDAY("Saturday"), SUNDAY("Sunday");
private String description; MONDAY("Monday"), TUESDAY("Tuesday"), WEDNESDAY("Wednesday"), THURSDAY("Thursday"), FRIDAY(
"Friday"), SATURDAY("Saturday"), SUNDAY("Sunday");
Weekday(String description) {
this.description = description; private String description;
}
Weekday(String description) {
public String toString() { this.description = description;
return description; }
}
public String toString() {
return description;
}
} }

View File

@ -1,4 +1,5 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
import org.junit.Test; import org.junit.Test;
import com.iluwatar.event.aggregator.App; import com.iluwatar.event.aggregator.App;
@ -10,9 +11,9 @@ import com.iluwatar.event.aggregator.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -4,32 +4,33 @@ import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
/** /**
* The Execute Around idiom specifies some code to be executed before and after * The Execute Around idiom specifies some code to be executed before and after a method. Typically
* a method. Typically the idiom is used when the API has methods to be executed in * the idiom is used when the API has methods to be executed in pairs, such as resource
* pairs, such as resource allocation/deallocation or lock acquisition/release. * allocation/deallocation or lock acquisition/release.
* <p> * <p>
* In this example, we have {@link SimpleFileWriter} class that opens and closes the file * In this example, we have {@link SimpleFileWriter} class that opens and closes the file for the
* for the user. The user specifies only what to do with the file by providing the * user. The user specifies only what to do with the file by providing the {@link FileWriterAction}
* {@link FileWriterAction} implementation. * implementation.
* *
*/ */
public class App { public class App {
/**
* Program entry point
* @param args command line args
* @throws IOException
*/
public static void main( String[] args ) throws IOException {
new SimpleFileWriter("testfile.txt", new FileWriterAction() { /**
* Program entry point
*
* @param args command line args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
@Override new SimpleFileWriter("testfile.txt", new FileWriterAction() {
public void writeFile(FileWriter writer) throws IOException {
writer.write("Hello"); @Override
writer.append(" "); public void writeFile(FileWriter writer) throws IOException {
writer.append("there!"); writer.write("Hello");
} writer.append(" ");
}); writer.append("there!");
} }
});
}
} }

View File

@ -10,6 +10,6 @@ import java.io.IOException;
*/ */
public interface FileWriterAction { public interface FileWriterAction {
void writeFile(FileWriter writer) throws IOException; void writeFile(FileWriter writer) throws IOException;
} }

View File

@ -5,19 +5,18 @@ import java.io.IOException;
/** /**
* *
* SimpleFileWriter handles opening and closing file for the user. The user * SimpleFileWriter handles opening and closing file for the user. The user only has to specify what
* only has to specify what to do with the file resource through {@link FileWriterAction} * to do with the file resource through {@link FileWriterAction} parameter.
* parameter.
* *
*/ */
public class SimpleFileWriter { public class SimpleFileWriter {
public SimpleFileWriter(String filename, FileWriterAction action) throws IOException { public SimpleFileWriter(String filename, FileWriterAction action) throws IOException {
FileWriter writer = new FileWriter(filename); FileWriter writer = new FileWriter(filename);
try { try {
action.writeFile(writer); action.writeFile(writer);
} finally { } finally {
writer.close(); writer.close();
} }
} }
} }

View File

@ -15,17 +15,17 @@ import com.iluwatar.execute.around.App;
* *
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() throws IOException { public void test() throws IOException {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
@Before @Before
@After @After
public void cleanup() { public void cleanup() {
File file = new File("testfile.txt"); File file = new File("testfile.txt");
file.delete(); file.delete();
} }
} }

View File

@ -2,27 +2,28 @@ package com.iluwatar.facade;
/** /**
* *
* The Facade design pattern is often used when a system is very complex or difficult * The Facade design pattern is often used when a system is very complex or difficult to understand
* to understand because the system has a large number of interdependent classes or * because the system has a large number of interdependent classes or its source code is
* its source code is unavailable. This pattern hides the complexities of the larger * unavailable. This pattern hides the complexities of the larger system and provides a simpler
* system and provides a simpler interface to the client. It typically involves a single * interface to the client. It typically involves a single wrapper class which contains a set of
* wrapper class which contains a set of members required by client. These members access * members required by client. These members access the system on behalf of the facade client and
* the system on behalf of the facade client and hide the implementation details. * hide the implementation details.
* <p> * <p>
* In this example the Facade is ({@link DwarvenGoldmineFacade}) and it provides a simpler * In this example the Facade is ({@link DwarvenGoldmineFacade}) and it provides a simpler interface
* interface to the goldmine subsystem. * to the goldmine subsystem.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade(); public static void main(String[] args) {
facade.startNewDay(); DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade();
facade.digOutGold(); facade.startNewDay();
facade.endDay(); facade.digOutGold();
} facade.endDay();
}
} }

View File

@ -7,14 +7,13 @@ package com.iluwatar.facade;
*/ */
public class DwarvenCartOperator extends DwarvenMineWorker { public class DwarvenCartOperator extends DwarvenMineWorker {
@Override @Override
public void work() { public void work() {
System.out.println(name() + " moves gold chunks out of the mine."); System.out.println(name() + " moves gold chunks out of the mine.");
} }
@Override
public String name() {
return "Dwarf cart operator";
}
@Override
public String name() {
return "Dwarf cart operator";
}
} }

View File

@ -7,14 +7,13 @@ package com.iluwatar.facade;
*/ */
public class DwarvenGoldDigger extends DwarvenMineWorker { public class DwarvenGoldDigger extends DwarvenMineWorker {
@Override @Override
public void work() { public void work() {
System.out.println(name() + " digs for gold."); System.out.println(name() + " digs for gold.");
} }
@Override
public String name() {
return "Dwarf gold digger";
}
@Override
public String name() {
return "Dwarf gold digger";
}
} }

View File

@ -6,40 +6,39 @@ import java.util.List;
/** /**
* *
* DwarvenGoldmineFacade provides a single interface * DwarvenGoldmineFacade provides a single interface through which users can operate the subsystems.
* through which users can operate the subsystems.
* *
* This makes the goldmine easier to operate and * This makes the goldmine easier to operate and cuts the dependencies from the goldmine user to the
* cuts the dependencies from the goldmine user to * subsystems.
* the subsystems.
* *
*/ */
public class DwarvenGoldmineFacade { public class DwarvenGoldmineFacade {
private final List<DwarvenMineWorker> workers; private final List<DwarvenMineWorker> workers;
public DwarvenGoldmineFacade() { public DwarvenGoldmineFacade() {
workers = new ArrayList<>(); workers = new ArrayList<>();
workers.add(new DwarvenGoldDigger()); workers.add(new DwarvenGoldDigger());
workers.add(new DwarvenCartOperator()); workers.add(new DwarvenCartOperator());
workers.add(new DwarvenTunnelDigger()); workers.add(new DwarvenTunnelDigger());
} }
public void startNewDay() { public void startNewDay() {
makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE); makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
} }
public void digOutGold() { public void digOutGold() {
makeActions(workers, DwarvenMineWorker.Action.WORK); makeActions(workers, DwarvenMineWorker.Action.WORK);
} }
public void endDay() { public void endDay() {
makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP); makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
} }
private void makeActions(Collection<DwarvenMineWorker> workers, DwarvenMineWorker.Action... actions) { private void makeActions(Collection<DwarvenMineWorker> workers,
for (DwarvenMineWorker worker : workers) { DwarvenMineWorker.Action... actions) {
worker.action(actions); for (DwarvenMineWorker worker : workers) {
} worker.action(actions);
} }
}
} }

View File

@ -7,56 +7,56 @@ package com.iluwatar.facade;
*/ */
public abstract class DwarvenMineWorker { public abstract class DwarvenMineWorker {
public void goToSleep() { public void goToSleep() {
System.out.println(name() + " goes to sleep."); System.out.println(name() + " goes to sleep.");
} }
public void wakeUp() { public void wakeUp() {
System.out.println(name() + " wakes up."); System.out.println(name() + " wakes up.");
} }
public void goHome() { public void goHome() {
System.out.println(name() + " goes home."); System.out.println(name() + " goes home.");
} }
public void goToMine() { public void goToMine() {
System.out.println(name() + " goes to the mine."); System.out.println(name() + " goes to the mine.");
} }
private void action(Action action) { private void action(Action action) {
switch (action) { switch (action) {
case GO_TO_SLEEP: case GO_TO_SLEEP:
goToSleep(); goToSleep();
break; break;
case WAKE_UP: case WAKE_UP:
wakeUp(); wakeUp();
break; break;
case GO_HOME: case GO_HOME:
goHome(); goHome();
break; break;
case GO_TO_MINE: case GO_TO_MINE:
goToMine(); goToMine();
break; break;
case WORK: case WORK:
work(); work();
break; break;
default: default:
System.out.println("Undefined action"); System.out.println("Undefined action");
break; break;
}
} }
}
public void action(Action... actions) { public void action(Action... actions) {
for (Action action : actions) { for (Action action : actions) {
action(action); action(action);
}
} }
}
public abstract void work(); public abstract void work();
public abstract String name(); public abstract String name();
static enum Action { static enum Action {
GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
} }
} }

View File

@ -7,14 +7,13 @@ package com.iluwatar.facade;
*/ */
public class DwarvenTunnelDigger extends DwarvenMineWorker { public class DwarvenTunnelDigger extends DwarvenMineWorker {
@Override @Override
public void work() { public void work() {
System.out.println(name() + " creates another promising tunnel."); System.out.println(name() + " creates another promising tunnel.");
} }
@Override
public String name() {
return "Dwarven tunnel digger";
}
@Override
public String name() {
return "Dwarven tunnel digger";
}
} }

View File

@ -11,9 +11,9 @@ import com.iluwatar.facade.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -2,39 +2,39 @@ package com.iluwatar.factory.method;
/** /**
* *
* The Factory Method is a creational design pattern which uses factory methods to deal * The Factory Method is a creational design pattern which uses factory methods to deal with the
* with the problem of creating objects without specifying the exact class of object * problem of creating objects without specifying the exact class of object that will be created.
* that will be created. This is done by creating objects via calling a factory * This is done by creating objects via calling a factory method either specified in an interface
* method either specified in an interface and implemented by child classes, or implemented * and implemented by child classes, or implemented in a base class and optionally overridden by
* in a base class and optionally overridden by derived classesrather than by calling a * derived classesrather than by calling a constructor.
* constructor.
* <p> * <p>
* In this Factory Method example we have an interface ({@link Blacksmith}) with a method for * In this Factory Method example we have an interface ({@link Blacksmith}) with a method for
* creating objects ({@link Blacksmith#manufactureWeapon}). The concrete subclasses * creating objects ({@link Blacksmith#manufactureWeapon}). The concrete subclasses (
* ({@link OrcBlacksmith}, {@link ElfBlacksmith}) then override the method to produce * {@link OrcBlacksmith}, {@link ElfBlacksmith}) then override the method to produce objects of
* objects of their liking. * their liking.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
Blacksmith blacksmith; public static void main(String[] args) {
Weapon weapon; Blacksmith blacksmith;
Weapon weapon;
blacksmith = new OrcBlacksmith(); blacksmith = new OrcBlacksmith();
weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR); weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
System.out.println(weapon); System.out.println(weapon);
weapon = blacksmith.manufactureWeapon(WeaponType.AXE); weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
System.out.println(weapon); System.out.println(weapon);
blacksmith = new ElfBlacksmith(); blacksmith = new ElfBlacksmith();
weapon = blacksmith.manufactureWeapon(WeaponType.SHORT_SWORD); weapon = blacksmith.manufactureWeapon(WeaponType.SHORT_SWORD);
System.out.println(weapon); System.out.println(weapon);
weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR); weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
System.out.println(weapon); System.out.println(weapon);
} }
} }

View File

@ -7,6 +7,6 @@ package com.iluwatar.factory.method;
*/ */
public interface Blacksmith { public interface Blacksmith {
Weapon manufactureWeapon(WeaponType weaponType); Weapon manufactureWeapon(WeaponType weaponType);
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.factory.method;
*/ */
public class ElfBlacksmith implements Blacksmith { public class ElfBlacksmith implements Blacksmith {
public Weapon manufactureWeapon(WeaponType weaponType) { public Weapon manufactureWeapon(WeaponType weaponType) {
return new ElfWeapon(weaponType); return new ElfWeapon(weaponType);
} }
} }

View File

@ -7,15 +7,14 @@ package com.iluwatar.factory.method;
*/ */
public class ElfWeapon implements Weapon { public class ElfWeapon implements Weapon {
private WeaponType weaponType; private WeaponType weaponType;
public ElfWeapon(WeaponType weaponType) { public ElfWeapon(WeaponType weaponType) {
this.weaponType = weaponType; this.weaponType = weaponType;
} }
@Override
public String toString() {
return "Elven " + weaponType;
}
@Override
public String toString() {
return "Elven " + weaponType;
}
} }

View File

@ -7,8 +7,7 @@ package com.iluwatar.factory.method;
*/ */
public class OrcBlacksmith implements Blacksmith { public class OrcBlacksmith implements Blacksmith {
public Weapon manufactureWeapon(WeaponType weaponType) { public Weapon manufactureWeapon(WeaponType weaponType) {
return new OrcWeapon(weaponType); return new OrcWeapon(weaponType);
} }
} }

View File

@ -7,15 +7,14 @@ package com.iluwatar.factory.method;
*/ */
public class OrcWeapon implements Weapon { public class OrcWeapon implements Weapon {
private WeaponType weaponType; private WeaponType weaponType;
public OrcWeapon(WeaponType weaponType) { public OrcWeapon(WeaponType weaponType) {
this.weaponType = weaponType; this.weaponType = weaponType;
} }
@Override
public String toString() {
return "Orcish " + weaponType;
}
@Override
public String toString() {
return "Orcish " + weaponType;
}
} }

View File

@ -7,16 +7,16 @@ package com.iluwatar.factory.method;
*/ */
public enum WeaponType { public enum WeaponType {
SHORT_SWORD("short sword"), SPEAR("spear"), AXE("axe"), UNDEFINED(""); SHORT_SWORD("short sword"), SPEAR("spear"), AXE("axe"), UNDEFINED("");
private String title; private String title;
WeaponType(String title) { WeaponType(String title) {
this.title = title; this.title = title;
} }
@Override @Override
public String toString() { public String toString() {
return title; return title;
} }
} }

View File

@ -11,9 +11,9 @@ import com.iluwatar.factory.method.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -11,13 +11,15 @@ import java.util.function.Predicate;
import static java.lang.String.valueOf; import static java.lang.String.valueOf;
/** /**
* The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those * The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API.
* interfaces tend to mimic domain specific languages, so they can nearly be read as human languages. * Those interfaces tend to mimic domain specific languages, so they can nearly be read as human
* languages.
* <p> * <p>
* In this example two implementations of a {@link FluentIterable} interface are given. The * In this example two implementations of a {@link FluentIterable} interface are given. The
* {@link SimpleFluentIterable} evaluates eagerly and would be too costly for real world applications. * {@link SimpleFluentIterable} evaluates eagerly and would be too costly for real world
* The {@link LazyFluentIterable} is evaluated on termination. Their usage is demonstrated with a * applications. The {@link LazyFluentIterable} is evaluated on termination. Their usage is
* simple number list that is filtered, transformed and collected. The result is printed afterwards. * demonstrated with a simple number list that is filtered, transformed and collected. The result is
* printed afterwards.
* *
*/ */
public class App { public class App {
@ -25,11 +27,9 @@ public class App {
public static void main(String[] args) { public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>(); List<Integer> integerList = new ArrayList<>();
integerList.addAll(Arrays.asList( integerList.addAll(Arrays.asList(1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2,
1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, -68, 45));
45, 23, 2, -68, 45
));
prettyPrint("The initial list contains: ", integerList); prettyPrint("The initial list contains: ", integerList);
List<Integer> firstFiveNegatives = List<Integer> firstFiveNegatives =

View File

@ -7,13 +7,13 @@ package com.iluwatar.flux.action;
*/ */
public abstract class Action { public abstract class Action {
private ActionType type; private ActionType type;
public Action(ActionType type) { public Action(ActionType type) {
this.type = type; this.type = type;
} }
public ActionType getType() { public ActionType getType() {
return type; return type;
} }
} }

View File

@ -7,6 +7,6 @@ package com.iluwatar.flux.action;
*/ */
public enum ActionType { public enum ActionType {
MENU_ITEM_SELECTED, CONTENT_CHANGED; MENU_ITEM_SELECTED, CONTENT_CHANGED;
} }

View File

@ -6,17 +6,18 @@ package com.iluwatar.flux.action;
* *
*/ */
public enum Content { public enum Content {
PRODUCTS("Products - This page lists the company's products."), COMPANY("Company - This page displays information about the company.");
private String title;
private Content(String title) { PRODUCTS("Products - This page lists the company's products."), COMPANY(
this.title = title; "Company - This page displays information about the company.");
}
private String title;
@Override
public String toString() { private Content(String title) {
return title; this.title = title;
} }
@Override
public String toString() {
return title;
}
} }

View File

@ -7,14 +7,14 @@ package com.iluwatar.flux.action;
*/ */
public class ContentAction extends Action { public class ContentAction extends Action {
private Content content; private Content content;
public ContentAction(Content content) { public ContentAction(Content content) {
super(ActionType.CONTENT_CHANGED); super(ActionType.CONTENT_CHANGED);
this.content = content; this.content = content;
} }
public Content getContent() { public Content getContent() {
return content; return content;
} }
} }

View File

@ -8,14 +8,14 @@ package com.iluwatar.flux.action;
*/ */
public class MenuAction extends Action { public class MenuAction extends Action {
private MenuItem menuItem; private MenuItem menuItem;
public MenuAction(MenuItem menuItem) { public MenuAction(MenuItem menuItem) {
super(ActionType.MENU_ITEM_SELECTED); super(ActionType.MENU_ITEM_SELECTED);
this.menuItem = menuItem; this.menuItem = menuItem;
} }
public MenuItem getMenuItem() { public MenuItem getMenuItem() {
return menuItem; return menuItem;
} }
} }

View File

@ -6,17 +6,17 @@ package com.iluwatar.flux.action;
* *
*/ */
public enum MenuItem { public enum MenuItem {
HOME("Home"), PRODUCTS("Products"), COMPANY("Company");
private String title;
MenuItem(String title) { HOME("Home"), PRODUCTS("Products"), COMPANY("Company");
this.title = title;
} private String title;
@Override MenuItem(String title) {
public String toString() { this.title = title;
return title; }
}
@Override
public String toString() {
return title;
}
} }

View File

@ -9,43 +9,45 @@ import com.iluwatar.flux.view.MenuView;
/** /**
* *
* Flux is the application architecture that Facebook uses for building client-side web * Flux is the application architecture that Facebook uses for building client-side web
* applications. Flux eschews MVC in favor of a unidirectional data flow. When a user interacts with * applications. Flux eschews MVC in favor of a unidirectional data flow. When a user interacts with
* a React view, the view propagates an action through a central dispatcher, to the various stores that * a React view, the view propagates an action through a central dispatcher, to the various stores
* hold the application's data and business logic, which updates all of the views that are affected. * that hold the application's data and business logic, which updates all of the views that are
* affected.
* <p> * <p>
* This example has two views: menu and content. They represent typical main menu and content area of * This example has two views: menu and content. They represent typical main menu and content area
* a web page. When menu item is clicked it triggers events through the dispatcher. The events are * of a web page. When menu item is clicked it triggers events through the dispatcher. The events
* received and handled by the stores updating their data as needed. The stores then notify the views * are received and handled by the stores updating their data as needed. The stores then notify the
* that they should rerender themselves. * views that they should rerender themselves.
* <p> * <p>
* http://facebook.github.io/flux/docs/overview.html * http://facebook.github.io/flux/docs/overview.html
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main( String[] args ) { */
public static void main(String[] args) {
// initialize and wire the system
MenuStore menuStore = new MenuStore(); // initialize and wire the system
Dispatcher.getInstance().registerStore(menuStore); MenuStore menuStore = new MenuStore();
ContentStore contentStore = new ContentStore(); Dispatcher.getInstance().registerStore(menuStore);
Dispatcher.getInstance().registerStore(contentStore); ContentStore contentStore = new ContentStore();
MenuView menuView = new MenuView(); Dispatcher.getInstance().registerStore(contentStore);
menuStore.registerView(menuView); MenuView menuView = new MenuView();
ContentView contentView = new ContentView(); menuStore.registerView(menuView);
contentStore.registerView(contentView); ContentView contentView = new ContentView();
contentStore.registerView(contentView);
// render initial view
menuView.render(); // render initial view
contentView.render(); menuView.render();
contentView.render();
// user clicks another menu item
// this triggers action dispatching and eventually causes views to render with new content // user clicks another menu item
menuView.itemClicked(MenuItem.COMPANY); // this triggers action dispatching and eventually causes views to render with new content
} menuView.itemClicked(MenuItem.COMPANY);
}
} }

View File

@ -16,37 +16,36 @@ import com.iluwatar.flux.store.Store;
* *
*/ */
public class Dispatcher { public class Dispatcher {
private static Dispatcher instance = new Dispatcher();
private List<Store> stores = new LinkedList<>();
private Dispatcher() {
}
public static Dispatcher getInstance() { private static Dispatcher instance = new Dispatcher();
return instance;
} private List<Store> stores = new LinkedList<>();
public void registerStore(Store store) { private Dispatcher() {}
stores.add(store);
} public static Dispatcher getInstance() {
return instance;
public void menuItemSelected(MenuItem menuItem) { }
dispatchAction(new MenuAction(menuItem));
switch (menuItem) { public void registerStore(Store store) {
case HOME: stores.add(store);
case PRODUCTS: }
default:
dispatchAction(new ContentAction(Content.PRODUCTS)); public void menuItemSelected(MenuItem menuItem) {
break; dispatchAction(new MenuAction(menuItem));
case COMPANY: switch (menuItem) {
dispatchAction(new ContentAction(Content.COMPANY)); case HOME:
break; case PRODUCTS:
} default:
} dispatchAction(new ContentAction(Content.PRODUCTS));
break;
private void dispatchAction(Action action) { case COMPANY:
stores.stream().forEach((store) -> store.onAction(action)); dispatchAction(new ContentAction(Content.COMPANY));
} break;
}
}
private void dispatchAction(Action action) {
stores.stream().forEach((store) -> store.onAction(action));
}
} }

View File

@ -12,18 +12,18 @@ import com.iluwatar.flux.action.ContentAction;
*/ */
public class ContentStore extends Store { public class ContentStore extends Store {
private Content content = Content.PRODUCTS; private Content content = Content.PRODUCTS;
@Override @Override
public void onAction(Action action) { public void onAction(Action action) {
if (action.getType().equals(ActionType.CONTENT_CHANGED)) { if (action.getType().equals(ActionType.CONTENT_CHANGED)) {
ContentAction contentAction = (ContentAction) action; ContentAction contentAction = (ContentAction) action;
content = contentAction.getContent(); content = contentAction.getContent();
notifyChange(); notifyChange();
} }
} }
public Content getContent() { public Content getContent() {
return content; return content;
} }
} }

View File

@ -12,18 +12,18 @@ import com.iluwatar.flux.action.MenuItem;
*/ */
public class MenuStore extends Store { public class MenuStore extends Store {
private MenuItem selected = MenuItem.HOME; private MenuItem selected = MenuItem.HOME;
@Override @Override
public void onAction(Action action) { public void onAction(Action action) {
if (action.getType().equals(ActionType.MENU_ITEM_SELECTED)) { if (action.getType().equals(ActionType.MENU_ITEM_SELECTED)) {
MenuAction menuAction = (MenuAction) action; MenuAction menuAction = (MenuAction) action;
selected = menuAction.getMenuItem(); selected = menuAction.getMenuItem();
notifyChange(); notifyChange();
} }
} }
public MenuItem getSelected() { public MenuItem getSelected() {
return selected; return selected;
} }
} }

View File

@ -12,16 +12,16 @@ import com.iluwatar.flux.view.View;
* *
*/ */
public abstract class Store { public abstract class Store {
private List<View> views = new LinkedList<>();
public abstract void onAction(Action action);
public void registerView(View view) { private List<View> views = new LinkedList<>();
views.add(view);
} public abstract void onAction(Action action);
protected void notifyChange() { public void registerView(View view) {
views.stream().forEach((view) -> view.storeChanged(this)); views.add(view);
} }
protected void notifyChange() {
views.stream().forEach((view) -> view.storeChanged(this));
}
} }

View File

@ -11,17 +11,17 @@ import com.iluwatar.flux.store.Store;
*/ */
public class ContentView implements View { public class ContentView implements View {
private Content content = Content.PRODUCTS; private Content content = Content.PRODUCTS;
@Override @Override
public void storeChanged(Store store) { public void storeChanged(Store store) {
ContentStore contentStore = (ContentStore) store; ContentStore contentStore = (ContentStore) store;
content = contentStore.getContent(); content = contentStore.getContent();
render(); render();
} }
@Override @Override
public void render() { public void render() {
System.out.println(content.toString()); System.out.println(content.toString());
} }
} }

View File

@ -12,27 +12,27 @@ import com.iluwatar.flux.store.Store;
*/ */
public class MenuView implements View { public class MenuView implements View {
private MenuItem selected = MenuItem.HOME; private MenuItem selected = MenuItem.HOME;
@Override
public void storeChanged(Store store) {
MenuStore menuStore = (MenuStore) store;
selected = menuStore.getSelected();
render();
}
@Override @Override
public void render() { public void storeChanged(Store store) {
for (MenuItem item: MenuItem.values()) { MenuStore menuStore = (MenuStore) store;
if (selected.equals(item)) { selected = menuStore.getSelected();
System.out.println(String.format("* %s", item.toString())); render();
} else { }
System.out.println(item.toString());
} @Override
} public void render() {
} for (MenuItem item : MenuItem.values()) {
if (selected.equals(item)) {
public void itemClicked(MenuItem item) { System.out.println(String.format("* %s", item.toString()));
Dispatcher.getInstance().menuItemSelected(item); } else {
} System.out.println(item.toString());
}
}
}
public void itemClicked(MenuItem item) {
Dispatcher.getInstance().menuItemSelected(item);
}
} }

View File

@ -9,7 +9,7 @@ import com.iluwatar.flux.store.Store;
*/ */
public interface View { public interface View {
public void storeChanged(Store store); public void storeChanged(Store store);
public void render(); public void render();
} }

View File

@ -10,10 +10,10 @@ import com.iluwatar.flux.app.App;
* *
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -5,53 +5,52 @@ import java.util.List;
/** /**
* *
* AlchemistShop holds potions on its shelves. * AlchemistShop holds potions on its shelves. It uses PotionFactory to provide the potions.
* It uses PotionFactory to provide the potions.
* *
*/ */
public class AlchemistShop { public class AlchemistShop {
private List<Potion> topShelf; private List<Potion> topShelf;
private List<Potion> bottomShelf; private List<Potion> bottomShelf;
public AlchemistShop() { public AlchemistShop() {
topShelf = new ArrayList<>(); topShelf = new ArrayList<>();
bottomShelf = new ArrayList<>(); bottomShelf = new ArrayList<>();
fillShelves(); fillShelves();
} }
private void fillShelves() { private void fillShelves() {
PotionFactory factory = new PotionFactory(); PotionFactory factory = new PotionFactory();
topShelf.add(factory.createPotion(PotionType.INVISIBILITY)); topShelf.add(factory.createPotion(PotionType.INVISIBILITY));
topShelf.add(factory.createPotion(PotionType.INVISIBILITY)); topShelf.add(factory.createPotion(PotionType.INVISIBILITY));
topShelf.add(factory.createPotion(PotionType.STRENGTH)); topShelf.add(factory.createPotion(PotionType.STRENGTH));
topShelf.add(factory.createPotion(PotionType.HEALING)); topShelf.add(factory.createPotion(PotionType.HEALING));
topShelf.add(factory.createPotion(PotionType.INVISIBILITY)); topShelf.add(factory.createPotion(PotionType.INVISIBILITY));
topShelf.add(factory.createPotion(PotionType.STRENGTH)); topShelf.add(factory.createPotion(PotionType.STRENGTH));
topShelf.add(factory.createPotion(PotionType.HEALING)); topShelf.add(factory.createPotion(PotionType.HEALING));
topShelf.add(factory.createPotion(PotionType.HEALING)); topShelf.add(factory.createPotion(PotionType.HEALING));
bottomShelf.add(factory.createPotion(PotionType.POISON)); bottomShelf.add(factory.createPotion(PotionType.POISON));
bottomShelf.add(factory.createPotion(PotionType.POISON)); bottomShelf.add(factory.createPotion(PotionType.POISON));
bottomShelf.add(factory.createPotion(PotionType.POISON)); bottomShelf.add(factory.createPotion(PotionType.POISON));
bottomShelf.add(factory.createPotion(PotionType.HOLY_WATER)); bottomShelf.add(factory.createPotion(PotionType.HOLY_WATER));
bottomShelf.add(factory.createPotion(PotionType.HOLY_WATER)); bottomShelf.add(factory.createPotion(PotionType.HOLY_WATER));
} }
public void enumerate() { public void enumerate() {
System.out.println("Enumerating top shelf potions\n"); System.out.println("Enumerating top shelf potions\n");
for (Potion p : topShelf) { for (Potion p : topShelf) {
p.drink(); p.drink();
} }
System.out.println("\nEnumerating bottom shelf potions\n"); System.out.println("\nEnumerating bottom shelf potions\n");
for (Potion p : bottomShelf) { for (Potion p : bottomShelf) {
p.drink(); p.drink();
} }
} }
} }

View File

@ -2,26 +2,27 @@ package com.iluwatar.flyweight;
/** /**
* *
* Flyweight pattern is useful when the program needs a huge amount of objects. * Flyweight pattern is useful when the program needs a huge amount of objects. It provides means to
* It provides means to decrease resource usage by sharing object instances. * decrease resource usage by sharing object instances.
* <p> * <p>
* In this example {@link AlchemistShop} has great amount of potions on its shelves. * In this example {@link AlchemistShop} has great amount of potions on its shelves. To fill the
* To fill the shelves {@link AlchemistShop} uses {@link PotionFactory} (which represents * shelves {@link AlchemistShop} uses {@link PotionFactory} (which represents the Flyweight in this
* the Flyweight in this example). Internally {@link PotionFactory} holds a map * example). Internally {@link PotionFactory} holds a map of the potions and lazily creates new ones
* of the potions and lazily creates new ones when requested. * when requested.
* <p> * <p>
* To enable safe sharing, between clients and threads, Flyweight objects must * To enable safe sharing, between clients and threads, Flyweight objects must be immutable.
* be immutable. Flyweight objects are by definition value objects. * Flyweight objects are by definition value objects.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
AlchemistShop alchemistShop = new AlchemistShop(); public static void main(String[] args) {
alchemistShop.enumerate(); AlchemistShop alchemistShop = new AlchemistShop();
} alchemistShop.enumerate();
}
} }

View File

@ -7,10 +7,8 @@ package com.iluwatar.flyweight;
*/ */
public class HealingPotion implements Potion { public class HealingPotion implements Potion {
@Override @Override
public void drink() { public void drink() {
System.out.println("You feel healed. (Potion=" System.out.println("You feel healed. (Potion=" + System.identityHashCode(this) + ")");
+ System.identityHashCode(this) + ")"); }
}
} }

View File

@ -7,10 +7,8 @@ package com.iluwatar.flyweight;
*/ */
public class HolyWaterPotion implements Potion { public class HolyWaterPotion implements Potion {
@Override @Override
public void drink() { public void drink() {
System.out.println("You feel blessed. (Potion=" System.out.println("You feel blessed. (Potion=" + System.identityHashCode(this) + ")");
+ System.identityHashCode(this) + ")"); }
}
} }

View File

@ -7,10 +7,8 @@ package com.iluwatar.flyweight;
*/ */
public class InvisibilityPotion implements Potion { public class InvisibilityPotion implements Potion {
@Override @Override
public void drink() { public void drink() {
System.out.println("You become invisible. (Potion=" System.out.println("You become invisible. (Potion=" + System.identityHashCode(this) + ")");
+ System.identityHashCode(this) + ")"); }
}
} }

View File

@ -7,10 +7,8 @@ package com.iluwatar.flyweight;
*/ */
public class PoisonPotion implements Potion { public class PoisonPotion implements Potion {
@Override @Override
public void drink() { public void drink() {
System.out.println("Urgh! This is poisonous. (Potion=" System.out.println("Urgh! This is poisonous. (Potion=" + System.identityHashCode(this) + ")");
+ System.identityHashCode(this) + ")"); }
}
} }

View File

@ -7,5 +7,5 @@ package com.iluwatar.flyweight;
*/ */
public interface Potion { public interface Potion {
void drink(); void drink();
} }

View File

@ -5,48 +5,47 @@ import java.util.Map;
/** /**
* *
* PotionFactory is the Flyweight in this example. * PotionFactory is the Flyweight in this example. It minimizes memory use by sharing object
* It minimizes memory use by sharing object instances. * instances. It holds a map of potion instances and new potions are created only when none of the
* It holds a map of potion instances and new potions * type already exists.
* are created only when none of the type already exists.
* *
*/ */
public class PotionFactory { public class PotionFactory {
private final Map<PotionType, Potion> potions; private final Map<PotionType, Potion> potions;
public PotionFactory() { public PotionFactory() {
potions = new EnumMap<>(PotionType.class); potions = new EnumMap<>(PotionType.class);
} }
Potion createPotion(PotionType type) { Potion createPotion(PotionType type) {
Potion potion = potions.get(type); Potion potion = potions.get(type);
if (potion == null) { if (potion == null) {
switch (type) { switch (type) {
case HEALING: case HEALING:
potion = new HealingPotion(); potion = new HealingPotion();
potions.put(type, potion); potions.put(type, potion);
break; break;
case HOLY_WATER: case HOLY_WATER:
potion = new HolyWaterPotion(); potion = new HolyWaterPotion();
potions.put(type, potion); potions.put(type, potion);
break; break;
case INVISIBILITY: case INVISIBILITY:
potion = new InvisibilityPotion(); potion = new InvisibilityPotion();
potions.put(type, potion); potions.put(type, potion);
break; break;
case POISON: case POISON:
potion = new PoisonPotion(); potion = new PoisonPotion();
potions.put(type, potion); potions.put(type, potion);
break; break;
case STRENGTH: case STRENGTH:
potion = new StrengthPotion(); potion = new StrengthPotion();
potions.put(type, potion); potions.put(type, potion);
break; break;
default: default:
break; break;
} }
} }
return potion; return potion;
} }
} }

View File

@ -7,5 +7,5 @@ package com.iluwatar.flyweight;
*/ */
public enum PotionType { public enum PotionType {
HEALING, INVISIBILITY, STRENGTH, HOLY_WATER, POISON HEALING, INVISIBILITY, STRENGTH, HOLY_WATER, POISON
} }

View File

@ -7,9 +7,8 @@ package com.iluwatar.flyweight;
*/ */
public class StrengthPotion implements Potion { public class StrengthPotion implements Potion {
@Override @Override
public void drink() { public void drink() {
System.out.println("You feel strong. (Potion=" System.out.println("You feel strong. (Potion=" + System.identityHashCode(this) + ")");
+ System.identityHashCode(this) + ")"); }
}
} }

View File

@ -11,9 +11,9 @@ import com.iluwatar.flyweight.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -8,122 +8,120 @@ import java.util.concurrent.LinkedBlockingQueue;
* {@link AsyncTask} and {@link AsynchronousService}. * {@link AsyncTask} and {@link AsynchronousService}.
* *
* <p> * <p>
* <i>PROBLEM</i> * <i>PROBLEM</i> <br/>
* <br/> * A concurrent system have a mixture of short duration, mid duration and long duration tasks. Mid
* A concurrent system have a mixture of short duration, mid duration and long duration tasks. * or long duration tasks should be performed asynchronously to meet quality of service
* Mid or long duration tasks should be performed asynchronously to meet quality of service
* requirements. * requirements.
* *
* <p><i>INTENT</i>
* <br/>
* The intent of this pattern is to separate the the synchronous and asynchronous processing
* in the concurrent application by introducing two intercommunicating layers - one for sync
* and one for async. This simplifies the programming without unduly affecting the performance.
*
* <p> * <p>
* <i>APPLICABILITY</i> * <i>INTENT</i> <br/>
* <br/> * The intent of this pattern is to separate the the synchronous and asynchronous processing in the
* concurrent application by introducing two intercommunicating layers - one for sync and one for
* async. This simplifies the programming without unduly affecting the performance.
*
* <p>
* <i>APPLICABILITY</i> <br/>
* <ul> * <ul>
* <li>UNIX network subsystems - In operating systems network operations are carried out * <li>UNIX network subsystems - In operating systems network operations are carried out
* asynchronously with help of hardware level interrupts.</li> * asynchronously with help of hardware level interrupts.</li>
* <li>CORBA - At the asynchronous layer one thread is associated with each socket that is * <li>CORBA - At the asynchronous layer one thread is associated with each socket that is connected
* connected to the client. Thread blocks waiting for CORBA requests from the client. On receiving * to the client. Thread blocks waiting for CORBA requests from the client. On receiving request it
* request it is inserted in the queuing layer which is then picked up by synchronous layer which * is inserted in the queuing layer which is then picked up by synchronous layer which processes the
* processes the request and sends response back to the client.</li> * request and sends response back to the client.</li>
* <li>Android AsyncTask framework - Framework provides a way to execute long running blocking calls, * <li>Android AsyncTask framework - Framework provides a way to execute long running blocking
* such as downloading a file, in background threads so that the UI thread remains free to respond * calls, such as downloading a file, in background threads so that the UI thread remains free to
* to user inputs.</i> * respond to user inputs.</i>
* </ul> * </ul>
* *
* <p> * <p>
* <i>IMPLEMENTATION</i> * <i>IMPLEMENTATION</i> <br/>
* <br/> * The main method creates an asynchronous service which does not block the main thread while the
* The main method creates an asynchronous service which does not block the main thread while * task is being performed. The main thread continues its work which is similar to Async Method
* the task is being performed. The main thread continues its work which is similar to Async Method * Invocation pattern. The difference between them is that there is a queuing layer between
* Invocation pattern. The difference between them is that there is a queuing layer between Asynchronous * Asynchronous layer and synchronous layer, which allows for different communication patterns
* layer and synchronous layer, which allows for different communication patterns between both layers. * between both layers. Such as Priority Queue can be used as queuing layer to prioritize the way
* Such as Priority Queue can be used as queuing layer to prioritize the way tasks are executed. * tasks are executed. Our implementation is just one simple way of implementing this pattern, there
* Our implementation is just one simple way of implementing this pattern, there are many variants possible * are many variants possible as described in its applications.
* as described in its applications.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
AsynchronousService service = new AsynchronousService(new LinkedBlockingQueue<>()); public static void main(String[] args) {
/* AsynchronousService service = new AsynchronousService(new LinkedBlockingQueue<>());
* A new task to calculate sum is received but as this is main thread, it should not block. /*
* So it passes it to the asynchronous task layer to compute and proceeds with handling other * A new task to calculate sum is received but as this is main thread, it should not block. So
* incoming requests. This is particularly useful when main thread is waiting on Socket to receive * it passes it to the asynchronous task layer to compute and proceeds with handling other
* new incoming requests and does not wait for particular request to be completed before responding * incoming requests. This is particularly useful when main thread is waiting on Socket to
* to new request. * receive new incoming requests and does not wait for particular request to be completed before
*/ * responding to new request.
service.execute(new ArithmeticSumTask(1000)); */
service.execute(new ArithmeticSumTask(1000));
/* New task received, lets pass that to async layer for computation. So both requests will be
* executed in parallel.
*/
service.execute(new ArithmeticSumTask(500));
service.execute(new ArithmeticSumTask(2000));
service.execute(new ArithmeticSumTask(1));
}
/**
*
* ArithmeticSumTask
*
*/
static class ArithmeticSumTask implements AsyncTask<Long> {
private long n;
public ArithmeticSumTask(long n) { /*
this.n = n; * New task received, lets pass that to async layer for computation. So both requests will be
} * executed in parallel.
*/
service.execute(new ArithmeticSumTask(500));
service.execute(new ArithmeticSumTask(2000));
service.execute(new ArithmeticSumTask(1));
}
/* /**
* This is the long running task that is performed in background. In our example *
* the long running task is calculating arithmetic sum with artificial delay. * ArithmeticSumTask
*/ *
@Override */
public Long call() throws Exception { static class ArithmeticSumTask implements AsyncTask<Long> {
return ap(n); private long n;
}
/* public ArithmeticSumTask(long n) {
* This will be called in context of the main thread where some validations can be this.n = n;
* done regarding the inputs. Such as it must be greater than 0. It's a small }
* computation which can be performed in main thread. If we did validated the input
* in background thread then we pay the cost of context switching
* which is much more than validating it in main thread.
*/
@Override
public void onPreCall() {
if (n < 0) {
throw new IllegalArgumentException("n is less than 0");
}
}
@Override /*
public void onPostCall(Long result) { * This is the long running task that is performed in background. In our example the long
// Handle the result of computation * running task is calculating arithmetic sum with artificial delay.
System.out.println(result); */
} @Override
public Long call() throws Exception {
return ap(n);
}
@Override /*
public void onError(Throwable throwable) { * This will be called in context of the main thread where some validations can be done
throw new IllegalStateException("Should not occur"); * regarding the inputs. Such as it must be greater than 0. It's a small computation which can
} * be performed in main thread. If we did validated the input in background thread then we pay
} * the cost of context switching which is much more than validating it in main thread.
*/
private static long ap(long i) { @Override
try { public void onPreCall() {
Thread.sleep(i); if (n < 0) {
} catch (InterruptedException e) { throw new IllegalArgumentException("n is less than 0");
} }
return (i) * (i + 1) / 2; }
}
@Override
public void onPostCall(Long result) {
// Handle the result of computation
System.out.println(result);
}
@Override
public void onError(Throwable throwable) {
throw new IllegalStateException("Should not occur");
}
}
private static long ap(long i) {
try {
Thread.sleep(i);
} catch (InterruptedException e) {
}
return (i) * (i + 1) / 2;
}
} }

View File

@ -3,42 +3,42 @@ package com.iluwatar.halfsynchalfasync;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
/** /**
* Represents some computation that is performed asynchronously and its result. * Represents some computation that is performed asynchronously and its result. The computation is
* The computation is typically done is background threads and the result is posted * typically done is background threads and the result is posted back in form of callback. The
* back in form of callback. The callback does not implement {@code isComplete}, {@code cancel} * callback does not implement {@code isComplete}, {@code cancel} as it is out of scope of this
* as it is out of scope of this pattern. * pattern.
* *
* @param <O> type of result * @param <O> type of result
*/ */
public interface AsyncTask<O> extends Callable<O> { public interface AsyncTask<O> extends Callable<O> {
/** /**
* Is called in context of caller thread before call to {@link #call()}. Large * Is called in context of caller thread before call to {@link #call()}. Large tasks should not be
* tasks should not be performed in this method as it will block the caller thread. * performed in this method as it will block the caller thread. Small tasks such as validations
* Small tasks such as validations can be performed here so that the performance penalty * can be performed here so that the performance penalty of context switching is not incurred in
* of context switching is not incurred in case of invalid requests. * case of invalid requests.
*/ */
void onPreCall(); void onPreCall();
/** /**
* A callback called after the result is successfully computed by {@link #call()}. In our * A callback called after the result is successfully computed by {@link #call()}. In our
* implementation this method is called in context of background thread but in some variants, * implementation this method is called in context of background thread but in some variants, such
* such as Android where only UI thread can change the state of UI widgets, this method is called * as Android where only UI thread can change the state of UI widgets, this method is called in
* in context of UI thread. * context of UI thread.
*/ */
void onPostCall(O result); void onPostCall(O result);
/** /**
* A callback called if computing the task resulted in some exception. This method * A callback called if computing the task resulted in some exception. This method is called when
* is called when either of {@link #call()} or {@link #onPreCall()} throw any exception. * either of {@link #call()} or {@link #onPreCall()} throw any exception.
* *
* @param throwable error cause * @param throwable error cause
*/ */
void onError(Throwable throwable); void onError(Throwable throwable);
/** /**
* This is where the computation of task should reside. This method is called in context * This is where the computation of task should reside. This method is called in context of
* of background thread. * background thread.
*/ */
@Override @Override
O call() throws Exception; O call() throws Exception;
} }

View File

@ -9,67 +9,67 @@ import java.util.concurrent.TimeUnit;
/** /**
* This is the asynchronous layer which does not block when a new request arrives. It just passes * This is the asynchronous layer which does not block when a new request arrives. It just passes
* the request to the synchronous layer which consists of a queue i.e. a {@link BlockingQueue} and * the request to the synchronous layer which consists of a queue i.e. a {@link BlockingQueue} and a
* a pool of threads i.e. {@link ThreadPoolExecutor}. Out of this pool of worker threads one of the * pool of threads i.e. {@link ThreadPoolExecutor}. Out of this pool of worker threads one of the
* thread picks up the task and executes it synchronously in background and the result is posted back * thread picks up the task and executes it synchronously in background and the result is posted
* to the caller via callback. * back to the caller via callback.
*/ */
public class AsynchronousService { public class AsynchronousService {
/*
* This represents the queuing layer as well as synchronous layer of the pattern. The thread
* pool contains worker threads which execute the tasks in blocking/synchronous manner. Long
* running tasks should be performed in the background which does not affect the performance of
* main thread.
*/
private ExecutorService service;
/** /*
* Creates an asynchronous service using {@code workQueue} as communication channel between * This represents the queuing layer as well as synchronous layer of the pattern. The thread pool
* asynchronous layer and synchronous layer. Different types of queues such as Priority queue, * contains worker threads which execute the tasks in blocking/synchronous manner. Long running
* can be used to control the pattern of communication between the layers. * tasks should be performed in the background which does not affect the performance of main
*/ * thread.
public AsynchronousService(BlockingQueue<Runnable> workQueue) { */
service = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, workQueue); private ExecutorService service;
}
/** /**
* A non-blocking method which performs the task provided in background and returns immediately. * Creates an asynchronous service using {@code workQueue} as communication channel between
* <p> * asynchronous layer and synchronous layer. Different types of queues such as Priority queue, can
* On successful completion of task the result is posted back using callback method * be used to control the pattern of communication between the layers.
* {@link AsyncTask#onPostCall(Object)}, if task execution is unable to complete normally */
* due to some exception then the reason for error is posted back using callback method public AsynchronousService(BlockingQueue<Runnable> workQueue) {
* {@link AsyncTask#onError(Throwable)}. service = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, workQueue);
* <p> }
* NOTE: The results are posted back in the context of background thread in this implementation.
*/
public <T> void execute(final AsyncTask<T> task) {
try {
// some small tasks such as validation can be performed here.
task.onPreCall();
} catch (Exception e) {
task.onError(e);
}
service.submit(new FutureTask<T>(task) {
@Override /**
protected void done() { * A non-blocking method which performs the task provided in background and returns immediately.
super.done(); * <p>
try { * On successful completion of task the result is posted back using callback method
/* called in context of background thread. There is other variant possible * {@link AsyncTask#onPostCall(Object)}, if task execution is unable to complete normally due to
* where result is posted back and sits in the queue of caller thread which * some exception then the reason for error is posted back using callback method
* then picks it up for processing. An example of such a system is Android OS, * {@link AsyncTask#onError(Throwable)}.
* where the UI elements can only be updated using UI thread. So result must be * <p>
* posted back in UI thread. * NOTE: The results are posted back in the context of background thread in this implementation.
*/ */
task.onPostCall(get()); public <T> void execute(final AsyncTask<T> task) {
} catch (InterruptedException e) { try {
// should not occur // some small tasks such as validation can be performed here.
} catch (ExecutionException e) { task.onPreCall();
task.onError(e.getCause()); } catch (Exception e) {
} task.onError(e);
} }
});
} service.submit(new FutureTask<T>(task) {
@Override
protected void done() {
super.done();
try {
/*
* called in context of background thread. There is other variant possible where result is
* posted back and sits in the queue of caller thread which then picks it up for
* processing. An example of such a system is Android OS, where the UI elements can only
* be updated using UI thread. So result must be posted back in UI thread.
*/
task.onPostCall(get());
} catch (InterruptedException e) {
// should not occur
} catch (ExecutionException e) {
task.onError(e.getCause());
}
}
});
}
} }

View File

@ -11,8 +11,8 @@ import org.junit.Test;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() throws InterruptedException, ExecutionException { public void test() throws InterruptedException, ExecutionException {
App.main(null); App.main(null);
} }
} }

View File

@ -1,46 +1,44 @@
package com.iluwatar.intercepting.filter; package com.iluwatar.intercepting.filter;
/** /**
* Base class for order processing filters. * Base class for order processing filters. Handles chain management.
* Handles chain management.
* *
*/ */
public abstract class AbstractFilter implements Filter { public abstract class AbstractFilter implements Filter {
private Filter next; private Filter next;
public AbstractFilter() {
}
public AbstractFilter(Filter next) { public AbstractFilter() {}
this.next = next;
}
@Override
public void setNext(Filter filter) {
this.next = filter;
}
@Override
public Filter getNext() {
return next;
}
@Override public AbstractFilter(Filter next) {
public Filter getLast() { this.next = next;
Filter last = this; }
while (last.getNext() != null) {
last = last.getNext(); @Override
} public void setNext(Filter filter) {
return last; this.next = filter;
} }
@Override @Override
public String execute(Order order) { public Filter getNext() {
if (getNext() != null) { return next;
return getNext().execute(order); }
} else {
return ""; @Override
} public Filter getLast() {
} Filter last = this;
while (last.getNext() != null) {
last = last.getNext();
}
return last;
}
@Override
public String execute(Order order) {
if (getNext() != null) {
return getNext().execute(order);
} else {
return "";
}
}
} }

View File

@ -1,19 +1,20 @@
package com.iluwatar.intercepting.filter; package com.iluwatar.intercepting.filter;
/** /**
* Concrete implementation of filter * Concrete implementation of filter This filter is responsible for checking/filtering the input in
* This filter is responsible for checking/filtering the input in the address field. * the address field.
*
* @author joshzambales * @author joshzambales
* *
*/ */
public class AddressFilter extends AbstractFilter { public class AddressFilter extends AbstractFilter {
@Override @Override
public String execute(Order order) { public String execute(Order order) {
String result = super.execute(order); String result = super.execute(order);
if (order.getAddress() == null || order.getAddress().isEmpty()) { if (order.getAddress() == null || order.getAddress().isEmpty()) {
return result + "Invalid address! "; return result + "Invalid address! ";
} else } else
return result; return result;
} }
} }

View File

@ -2,50 +2,46 @@ package com.iluwatar.intercepting.filter;
/** /**
* *
* When a request enters a Web application, it often must pass several entrance * When a request enters a Web application, it often must pass several entrance tests prior to the
* tests prior to the main processing stage. For example, * main processing stage. For example, - Has the client been authenticated? - Does the client have a
* - Has the client been authenticated? * valid session? - Is the client's IP address from a trusted network? - Does the request path
* - Does the client have a valid session? * violate any constraints? - What encoding does the client use to send the data? - Do we support
* - Is the client's IP address from a trusted network? * the browser type of the client? Some of these checks are tests, resulting in a yes or no answer
* - Does the request path violate any constraints? * that determines whether processing will continue. Other checks manipulate the incoming data
* - What encoding does the client use to send the data?
* - Do we support the browser type of the client?
* Some of these checks are tests, resulting in a yes or no answer that determines
* whether processing will continue. Other checks manipulate the incoming data
* stream into a form suitable for processing. * stream into a form suitable for processing.
* <p> * <p>
* The classic solution consists of a series of conditional checks, with any failed * The classic solution consists of a series of conditional checks, with any failed check aborting
* check aborting the request. Nested if/else statements are a standard strategy, * the request. Nested if/else statements are a standard strategy, but this solution leads to code
* but this solution leads to code fragility and a copy-and-paste style of programming, * fragility and a copy-and-paste style of programming, because the flow of the filtering and the
* because the flow of the filtering and the action of the filters is compiled into * action of the filters is compiled into the application.
* the application.
* <p> * <p>
* The key to solving this problem in a flexible and unobtrusive manner is to have a * The key to solving this problem in a flexible and unobtrusive manner is to have a simple
* simple mechanism for adding and removing processing components, in which each * mechanism for adding and removing processing components, in which each component completes a
* component completes a specific filtering action. This is the Intercepting Filter * specific filtering action. This is the Intercepting Filter pattern in action.
* pattern in action.
* <p> * <p>
* In this example we check whether the order request is valid through pre-processing * In this example we check whether the order request is valid through pre-processing done via
* done via {@link Filter}. Each field has its own corresponding {@link Filter} * {@link Filter}. Each field has its own corresponding {@link Filter}
* <p> * <p>
*
* @author joshzambales * @author joshzambales
* *
*/ */
public class App{ public class App {
/**
* Program entry point
* @param args command line args
*/
public static void main(String[] args) {
FilterManager filterManager = new FilterManager(new Target());
filterManager.addFilter(new NameFilter());
filterManager.addFilter(new ContactFilter());
filterManager.addFilter(new AddressFilter());
filterManager.addFilter(new DepositFilter());
filterManager.addFilter(new OrderFilter());
Client client = new Client(); /**
client.setFilterManager(filterManager); * Program entry point
} *
* @param args command line args
*/
public static void main(String[] args) {
FilterManager filterManager = new FilterManager(new Target());
filterManager.addFilter(new NameFilter());
filterManager.addFilter(new ContactFilter());
filterManager.addFilter(new AddressFilter());
filterManager.addFilter(new DepositFilter());
filterManager.addFilter(new OrderFilter());
Client client = new Client();
client.setFilterManager(filterManager);
}
} }

View File

@ -15,93 +15,95 @@ import javax.swing.JTextField;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
/** /**
* The Client class is responsible for handling the input and running them through filters inside the {@link FilterManager}. * The Client class is responsible for handling the input and running them through filters inside
* the {@link FilterManager}.
* *
* This is where {@link Filter}s come to play as the client pre-processes the request before being displayed in the {@link Target}. * This is where {@link Filter}s come to play as the client pre-processes the request before being
* displayed in the {@link Target}.
* *
* @author joshzambales * @author joshzambales
* *
*/ */
public class Client extends JFrame { public class Client extends JFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private FilterManager filterManager; private FilterManager filterManager;
private JLabel jl; private JLabel jl;
private JTextField[] jtFields; private JTextField[] jtFields;
private JTextArea[] jtAreas; private JTextArea[] jtAreas;
private JButton clearButton, processButton; private JButton clearButton, processButton;
public Client() { public Client() {
super("Client System"); super("Client System");
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 300); setSize(300, 300);
jl = new JLabel("RUNNING..."); jl = new JLabel("RUNNING...");
jtFields = new JTextField[3]; jtFields = new JTextField[3];
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
jtFields[i] = new JTextField(); jtFields[i] = new JTextField();
} }
jtAreas = new JTextArea[2]; jtAreas = new JTextArea[2];
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
jtAreas[i] = new JTextArea(); jtAreas[i] = new JTextArea();
} }
clearButton = new JButton("Clear"); clearButton = new JButton("Clear");
processButton = new JButton("Process"); processButton = new JButton("Process");
setup(); setup();
} }
private void setup() { private void setup() {
setLayout(new BorderLayout()); setLayout(new BorderLayout());
JPanel panel = new JPanel(); JPanel panel = new JPanel();
add(jl, BorderLayout.SOUTH); add(jl, BorderLayout.SOUTH);
add(panel, BorderLayout.CENTER); add(panel, BorderLayout.CENTER);
panel.setLayout(new GridLayout(6, 2)); panel.setLayout(new GridLayout(6, 2));
panel.add(new JLabel("Name")); panel.add(new JLabel("Name"));
panel.add(jtFields[0]); panel.add(jtFields[0]);
panel.add(new JLabel("Contact Number")); panel.add(new JLabel("Contact Number"));
panel.add(jtFields[1]); panel.add(jtFields[1]);
panel.add(new JLabel("Address")); panel.add(new JLabel("Address"));
panel.add(jtAreas[0]); panel.add(jtAreas[0]);
panel.add(new JLabel("Deposit Number")); panel.add(new JLabel("Deposit Number"));
panel.add(jtFields[2]); panel.add(jtFields[2]);
panel.add(new JLabel("Order")); panel.add(new JLabel("Order"));
panel.add(jtAreas[1]); panel.add(jtAreas[1]);
panel.add(clearButton); panel.add(clearButton);
panel.add(processButton); panel.add(processButton);
clearButton.addActionListener(new ActionListener() { clearButton.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
for (JTextArea i : jtAreas) { for (JTextArea i : jtAreas) {
i.setText(""); i.setText("");
} }
for (JTextField i : jtFields) { for (JTextField i : jtFields) {
i.setText(""); i.setText("");
} }
} }
}); });
processButton.addActionListener(new ActionListener() { processButton.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Order order = new Order(jtFields[0].getText(), jtFields[1] Order order =
.getText(), jtAreas[0].getText(), new Order(jtFields[0].getText(), jtFields[1].getText(), jtAreas[0].getText(),
jtFields[2].getText(), jtAreas[1].getText()); jtFields[2].getText(), jtAreas[1].getText());
jl.setText(sendRequest(order)); jl.setText(sendRequest(order));
} }
}); });
JRootPane rootPane = SwingUtilities.getRootPane(processButton); JRootPane rootPane = SwingUtilities.getRootPane(processButton);
rootPane.setDefaultButton(processButton); rootPane.setDefaultButton(processButton);
setVisible(true); setVisible(true);
} }
public void setFilterManager(FilterManager filterManager) { public void setFilterManager(FilterManager filterManager) {
this.filterManager = filterManager; this.filterManager = filterManager;
} }
public String sendRequest(Order order) { public String sendRequest(Order order) {
return filterManager.filterRequest(order); return filterManager.filterRequest(order);
} }
} }

View File

@ -1,24 +1,24 @@
package com.iluwatar.intercepting.filter; package com.iluwatar.intercepting.filter;
/** /**
* Concrete implementation of filter * Concrete implementation of filter This filter checks for the contact field in which it checks if
* This filter checks for the contact field in which it checks if the input consist of numbers * the input consist of numbers and it also checks if the input follows the length constraint (11
* and it also checks if the input follows the length constraint (11 digits) * digits)
*
* @author joshzambales * @author joshzambales
* *
*/ */
public class ContactFilter extends AbstractFilter { public class ContactFilter extends AbstractFilter {
@Override @Override
public String execute(Order order) { public String execute(Order order) {
String result = super.execute(order); String result = super.execute(order);
if (order.getContactNumber() == null if (order.getContactNumber() == null || order.getContactNumber().isEmpty()
|| order.getContactNumber().isEmpty() || order.getContactNumber().matches(".*[^\\d]+.*")
|| order.getContactNumber().matches(".*[^\\d]+.*") || order.getContactNumber().length() != 11) {
|| order.getContactNumber().length() != 11) { return result + "Invalid contact number! ";
return result + "Invalid contact number! "; } else {
} else { return result;
return result; }
} }
}
} }

View File

@ -1,20 +1,20 @@
package com.iluwatar.intercepting.filter; package com.iluwatar.intercepting.filter;
/** /**
* Concrete implementation of filter * Concrete implementation of filter This checks for the deposit code
* This checks for the deposit code *
* @author joshzambales * @author joshzambales
* *
*/ */
public class DepositFilter extends AbstractFilter { public class DepositFilter extends AbstractFilter {
@Override @Override
public String execute(Order order) { public String execute(Order order) {
String result = super.execute(order); String result = super.execute(order);
if (order.getDepositNumber() == null || order.getDepositNumber().isEmpty()) { if (order.getDepositNumber() == null || order.getDepositNumber().isEmpty()) {
return result + "Invalid deposit number! "; return result + "Invalid deposit number! ";
} else { } else {
return result; return result;
} }
} }
} }

View File

@ -1,37 +1,40 @@
package com.iluwatar.intercepting.filter; package com.iluwatar.intercepting.filter;
/** /**
* Filters perform certain tasks prior or after execution of * Filters perform certain tasks prior or after execution of request by request handler. In this
* request by request handler. In this case, before the request is handled by * case, before the request is handled by the target, the request undergoes through each Filter
* the target, the request undergoes through each Filter
* *
* @author joshzambales * @author joshzambales
* *
*/ */
public interface Filter { public interface Filter {
/** /**
* Execute order processing filter. * Execute order processing filter.
* @param order *
* @return empty string on success, otherwise error message. * @param order
*/ * @return empty string on success, otherwise error message.
String execute(Order order); */
String execute(Order order);
/**
* Set next filter in chain after this. /**
* @param filter * Set next filter in chain after this.
*/ *
void setNext(Filter filter); * @param filter
*/
/** void setNext(Filter filter);
* Get next filter in chain after this.
* @return /**
*/ * Get next filter in chain after this.
Filter getNext(); *
* @return
/** */
* Get last filter in the chain. Filter getNext();
* @return
*/ /**
Filter getLast(); * Get last filter in the chain.
*
* @return
*/
Filter getLast();
} }

View File

@ -1,34 +1,34 @@
package com.iluwatar.intercepting.filter; package com.iluwatar.intercepting.filter;
/** /**
* Filter Chain carries multiple filters and help to execute them in defined order on target. * Filter Chain carries multiple filters and help to execute them in defined order on target.
* *
* @author joshzambales * @author joshzambales
*/ */
public class FilterChain { public class FilterChain {
private Filter chain;
private final Target target;
public FilterChain(Target target) { private Filter chain;
this.target = target;
}
public void addFilter(Filter filter) { private final Target target;
if (chain == null) {
chain = filter;
} else {
chain.getLast().setNext(filter);
}
}
public String execute(Order order) { public FilterChain(Target target) {
if (chain != null) { this.target = target;
return chain.execute(order); }
} else {
return "RUNNING..."; public void addFilter(Filter filter) {
} if (chain == null) {
} chain = filter;
} else {
chain.getLast().setNext(filter);
}
}
public String execute(Order order) {
if (chain != null) {
return chain.execute(order);
} else {
return "RUNNING...";
}
}
} }

View File

@ -7,18 +7,18 @@ package com.iluwatar.intercepting.filter;
* *
*/ */
public class FilterManager { public class FilterManager {
private FilterChain filterChain;
public FilterManager(Target target) { private FilterChain filterChain;
filterChain = new FilterChain(target);
}
public void addFilter(Filter filter) { public FilterManager(Target target) {
filterChain.addFilter(filter); filterChain = new FilterChain(target);
} }
public String filterRequest(Order order) { public void addFilter(Filter filter) {
return filterChain.execute(order); filterChain.addFilter(filter);
} }
public String filterRequest(Order order) {
return filterChain.execute(order);
}
} }

View File

@ -1,21 +1,22 @@
package com.iluwatar.intercepting.filter; package com.iluwatar.intercepting.filter;
/** /**
* Concrete implementation of filter. This filter checks if the input in the Name * Concrete implementation of filter. This filter checks if the input in the Name field is valid.
* field is valid. (alphanumeric) * (alphanumeric)
* *
* @author joshzambales * @author joshzambales
* *
*/ */
public class NameFilter extends AbstractFilter { public class NameFilter extends AbstractFilter {
@Override @Override
public String execute(Order order) { public String execute(Order order) {
String result = super.execute(order); String result = super.execute(order);
if (order.getName() == null || order.getName().isEmpty() || order.getName().matches(".*[^\\w|\\s]+.*")) { if (order.getName() == null || order.getName().isEmpty()
return result + "Invalid order! "; || order.getName().matches(".*[^\\w|\\s]+.*")) {
} else { return result + "Invalid order! ";
return result; } else {
} return result;
} }
}
} }

View File

@ -6,60 +6,59 @@ package com.iluwatar.intercepting.filter;
*/ */
public class Order { public class Order {
private String name; private String name;
private String contactNumber; private String contactNumber;
private String address; private String address;
private String depositNumber; private String depositNumber;
private String order; private String order;
public Order() {
}
public Order(String name, String contactNumber, String address, String depositNumber, String order) { public Order() {}
this.name = name;
this.contactNumber = contactNumber;
this.address = address;
this.depositNumber = depositNumber;
this.order = order;
}
public String getName() {
return name;
}
public void setName(String name) { public Order(String name, String contactNumber, String address, String depositNumber, String order) {
this.name = name; this.name = name;
} this.contactNumber = contactNumber;
this.address = address;
this.depositNumber = depositNumber;
this.order = order;
}
public String getContactNumber() { public String getName() {
return contactNumber; return name;
} }
public void setContactNumber(String contactNumber) { public void setName(String name) {
this.contactNumber = contactNumber; this.name = name;
} }
public String getAddress() { public String getContactNumber() {
return address; return contactNumber;
} }
public void setAddress(String address) { public void setContactNumber(String contactNumber) {
this.address = address; this.contactNumber = contactNumber;
} }
public String getDepositNumber() { public String getAddress() {
return depositNumber; return address;
} }
public void setDepositNumber(String depositNumber) { public void setAddress(String address) {
this.depositNumber = depositNumber; this.address = address;
} }
public String getOrder() { public String getDepositNumber() {
return order; return depositNumber;
} }
public void setOrder(String order) { public void setDepositNumber(String depositNumber) {
this.order = order; this.depositNumber = depositNumber;
} }
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
} }

View File

@ -7,14 +7,14 @@ package com.iluwatar.intercepting.filter;
* *
*/ */
public class OrderFilter extends AbstractFilter { public class OrderFilter extends AbstractFilter {
@Override @Override
public String execute(Order order) { public String execute(Order order) {
String result = super.execute(order); String result = super.execute(order);
if (order.getOrder() == null || order.getOrder().isEmpty()) { if (order.getOrder() == null || order.getOrder().isEmpty()) {
return result + "Invalid order! "; return result + "Invalid order! ";
} else { } else {
return result; return result;
} }
} }
} }

View File

@ -22,57 +22,57 @@ import javax.swing.table.DefaultTableModel;
*/ */
public class Target extends JFrame { public class Target extends JFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private JTable jt; private JTable jt;
private JScrollPane jsp; private JScrollPane jsp;
private DefaultTableModel dtm; private DefaultTableModel dtm;
private JButton del; private JButton del;
public Target() { public Target() {
super("Order System"); super("Order System");
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480); setSize(640, 480);
dtm = new DefaultTableModel(new Object[] { "Name", "Contact Number", dtm =
"Address", "Deposit Number", "Order" }, 0); new DefaultTableModel(new Object[] {"Name", "Contact Number", "Address", "Deposit Number",
jt = new JTable(dtm); "Order"}, 0);
del = new JButton("Delete"); jt = new JTable(dtm);
setup(); del = new JButton("Delete");
} setup();
}
private void setup() { private void setup() {
setLayout(new BorderLayout()); setLayout(new BorderLayout());
JPanel bot = new JPanel(); JPanel bot = new JPanel();
add(jt.getTableHeader(), BorderLayout.NORTH); add(jt.getTableHeader(), BorderLayout.NORTH);
bot.setLayout(new BorderLayout()); bot.setLayout(new BorderLayout());
bot.add(del, BorderLayout.EAST); bot.add(del, BorderLayout.EAST);
add(bot, BorderLayout.SOUTH); add(bot, BorderLayout.SOUTH);
jsp = new JScrollPane(jt); jsp = new JScrollPane(jt);
jsp.setPreferredSize(new Dimension(500, 250)); jsp.setPreferredSize(new Dimension(500, 250));
add(jsp, BorderLayout.CENTER); add(jsp, BorderLayout.CENTER);
del.addActionListener(new DListener()); del.addActionListener(new DListener());
JRootPane rootPane = SwingUtilities.getRootPane(del); JRootPane rootPane = SwingUtilities.getRootPane(del);
rootPane.setDefaultButton(del); rootPane.setDefaultButton(del);
setVisible(true); setVisible(true);
} }
public void execute(String[] request) { public void execute(String[] request) {
dtm.addRow(new Object[] { request[0], request[1], request[2], dtm.addRow(new Object[] {request[0], request[1], request[2], request[3], request[4]});
request[3], request[4] }); }
}
class DListener implements ActionListener { class DListener implements ActionListener {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int temp = jt.getSelectedRow(); int temp = jt.getSelectedRow();
if (temp == -1) if (temp == -1)
return; return;
int temp2 = jt.getSelectedRowCount(); int temp2 = jt.getSelectedRowCount();
for (int i = 0; i < temp2; i++) { for (int i = 0; i < temp2; i++) {
dtm.removeRow(temp); dtm.removeRow(temp);
} }
} }
} }
} }

View File

@ -11,9 +11,9 @@ import com.iluwatar.intercepting.filter.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -4,75 +4,66 @@ import java.util.Stack;
/** /**
* *
* The Interpreter pattern is a design pattern that specifies how to evaluate sentences * The Interpreter pattern is a design pattern that specifies how to evaluate sentences in a
* in a language. The basic idea is to have a class for each symbol (terminal or nonterminal) * language. The basic idea is to have a class for each symbol (terminal or nonterminal) in a
* in a specialized computer language. The syntax tree of a sentence in the language is an * specialized computer language. The syntax tree of a sentence in the language is an instance of
* instance of the composite pattern and is used to evaluate (interpret) the sentence for a * the composite pattern and is used to evaluate (interpret) the sentence for a client.
* client.
* <p> * <p>
* In this example we use the Interpreter pattern to break sentences into expressions * In this example we use the Interpreter pattern to break sentences into expressions (
* ({@link Expression}) that can be evaluated and as a whole form the result. * {@link Expression}) that can be evaluated and as a whole form the result.
* *
*/ */
public class App { public class App {
/** /**
* *
* Program entry point. * Program entry point.
* <p> * <p>
* Expressions can be evaluated using prefix, infix or postfix notations * Expressions can be evaluated using prefix, infix or postfix notations This sample uses postfix,
* This sample uses postfix, where operator comes after the operands * where operator comes after the operands
* *
* @param args command line args * @param args command line args
* *
*/ */
public static void main(String[] args) { public static void main(String[] args) {
String tokenString = "4 3 2 - 1 + *"; String tokenString = "4 3 2 - 1 + *";
Stack<Expression> stack = new Stack<>(); Stack<Expression> stack = new Stack<>();
String[] tokenList = tokenString.split(" "); String[] tokenList = tokenString.split(" ");
for (String s : tokenList) { for (String s : tokenList) {
if (isOperator(s)) { if (isOperator(s)) {
Expression rightExpression = stack.pop(); Expression rightExpression = stack.pop();
Expression leftExpression = stack.pop(); Expression leftExpression = stack.pop();
System.out System.out.println(String.format("popped from stack left: %d right: %d",
.println(String.format( leftExpression.interpret(), rightExpression.interpret()));
"popped from stack left: %d right: %d", Expression operator = getOperatorInstance(s, leftExpression, rightExpression);
leftExpression.interpret(), System.out.println(String.format("operator: %s", operator));
rightExpression.interpret())); int result = operator.interpret();
Expression operator = getOperatorInstance(s, leftExpression, NumberExpression resultExpression = new NumberExpression(result);
rightExpression); stack.push(resultExpression);
System.out.println(String.format("operator: %s", operator)); System.out.println(String.format("push result to stack: %d", resultExpression.interpret()));
int result = operator.interpret(); } else {
NumberExpression resultExpression = new NumberExpression(result); Expression i = new NumberExpression(s);
stack.push(resultExpression); stack.push(i);
System.out.println(String.format("push result to stack: %d", System.out.println(String.format("push to stack: %d", i.interpret()));
resultExpression.interpret())); }
} else { }
Expression i = new NumberExpression(s); System.out.println(String.format("result: %d", stack.pop().interpret()));
stack.push(i); }
System.out.println(String.format("push to stack: %d",
i.interpret()));
}
}
System.out
.println(String.format("result: %d", stack.pop().interpret()));
}
public static boolean isOperator(String s) { public static boolean isOperator(String s) {
return s.equals("+") || s.equals("-") || s.equals("*"); return s.equals("+") || s.equals("-") || s.equals("*");
} }
public static Expression getOperatorInstance(String s, Expression left, public static Expression getOperatorInstance(String s, Expression left, Expression right) {
Expression right) { switch (s) {
switch (s) { case "+":
case "+": return new PlusExpression(left, right);
return new PlusExpression(left, right); case "-":
case "-": return new MinusExpression(left, right);
return new MinusExpression(left, right); case "*":
case "*": return new MultiplyExpression(left, right);
return new MultiplyExpression(left, right); }
} return null;
return null; }
}
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.interpreter;
*/ */
public abstract class Expression { public abstract class Expression {
public abstract int interpret(); public abstract int interpret();
@Override @Override
public abstract String toString(); public abstract String toString();
} }

View File

@ -7,22 +7,22 @@ package com.iluwatar.interpreter;
*/ */
public class MinusExpression extends Expression { public class MinusExpression extends Expression {
private Expression leftExpression; private Expression leftExpression;
private Expression rightExpression; private Expression rightExpression;
public MinusExpression(Expression leftExpression, Expression rightExpression) { public MinusExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression; this.leftExpression = leftExpression;
this.rightExpression = rightExpression; this.rightExpression = rightExpression;
} }
@Override @Override
public int interpret() { public int interpret() {
return leftExpression.interpret() - rightExpression.interpret(); return leftExpression.interpret() - rightExpression.interpret();
} }
@Override @Override
public String toString() { public String toString() {
return "-"; return "-";
} }
} }

View File

@ -7,23 +7,22 @@ package com.iluwatar.interpreter;
*/ */
public class MultiplyExpression extends Expression { public class MultiplyExpression extends Expression {
private Expression leftExpression; private Expression leftExpression;
private Expression rightExpression; private Expression rightExpression;
public MultiplyExpression(Expression leftExpression, public MultiplyExpression(Expression leftExpression, Expression rightExpression) {
Expression rightExpression) { this.leftExpression = leftExpression;
this.leftExpression = leftExpression; this.rightExpression = rightExpression;
this.rightExpression = rightExpression; }
}
@Override @Override
public int interpret() { public int interpret() {
return leftExpression.interpret() * rightExpression.interpret(); return leftExpression.interpret() * rightExpression.interpret();
} }
@Override @Override
public String toString() { public String toString() {
return "*"; return "*";
} }
} }

View File

@ -7,24 +7,23 @@ package com.iluwatar.interpreter;
*/ */
public class NumberExpression extends Expression { public class NumberExpression extends Expression {
private int number; private int number;
public NumberExpression(int number) { public NumberExpression(int number) {
this.number = number; this.number = number;
} }
public NumberExpression(String s) { public NumberExpression(String s) {
this.number = Integer.parseInt(s); this.number = Integer.parseInt(s);
} }
@Override @Override
public int interpret() { public int interpret() {
return number; return number;
} }
@Override
public String toString() {
return "number";
}
@Override
public String toString() {
return "number";
}
} }

View File

@ -7,22 +7,21 @@ package com.iluwatar.interpreter;
*/ */
public class PlusExpression extends Expression { public class PlusExpression extends Expression {
private Expression leftExpression; private Expression leftExpression;
private Expression rightExpression; private Expression rightExpression;
public PlusExpression(Expression leftExpression, Expression rightExpression) { public PlusExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression; this.leftExpression = leftExpression;
this.rightExpression = rightExpression; this.rightExpression = rightExpression;
} }
@Override @Override
public int interpret() { public int interpret() {
return leftExpression.interpret() + rightExpression.interpret(); return leftExpression.interpret() + rightExpression.interpret();
} }
@Override
public String toString() {
return "+";
}
@Override
public String toString() {
return "+";
}
} }

View File

@ -11,9 +11,9 @@ import com.iluwatar.interpreter.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -2,48 +2,48 @@ package com.iluwatar.iterator;
/** /**
* *
* The Iterator pattern is a design pattern in which an iterator is used to * The Iterator pattern is a design pattern in which an iterator is used to traverse a container and
* traverse a container and access the container's elements. The Iterator pattern * access the container's elements. The Iterator pattern decouples algorithms from containers.
* decouples algorithms from containers.
* <p> * <p>
* In this example the Iterator ({@link ItemIterator}) adds abstraction layer on * In this example the Iterator ({@link ItemIterator}) adds abstraction layer on top of a collection
* top of a collection ({@link TreasureChest}). This way the collection can change * ({@link TreasureChest}). This way the collection can change its internal implementation without
* its internal implementation without affecting its clients. * affecting its clients.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
TreasureChest chest = new TreasureChest(); public static void main(String[] args) {
TreasureChest chest = new TreasureChest();
ItemIterator ringIterator = chest.Iterator(ItemType.RING); ItemIterator ringIterator = chest.Iterator(ItemType.RING);
while (ringIterator.hasNext()) { while (ringIterator.hasNext()) {
System.out.println(ringIterator.next()); System.out.println(ringIterator.next());
} }
System.out.println("----------"); System.out.println("----------");
ItemIterator potionIterator = chest.Iterator(ItemType.POTION); ItemIterator potionIterator = chest.Iterator(ItemType.POTION);
while (potionIterator.hasNext()) { while (potionIterator.hasNext()) {
System.out.println(potionIterator.next()); System.out.println(potionIterator.next());
} }
System.out.println("----------"); System.out.println("----------");
ItemIterator weaponIterator = chest.Iterator(ItemType.WEAPON); ItemIterator weaponIterator = chest.Iterator(ItemType.WEAPON);
while (weaponIterator.hasNext()) { while (weaponIterator.hasNext()) {
System.out.println(weaponIterator.next()); System.out.println(weaponIterator.next());
} }
System.out.println("----------"); System.out.println("----------");
ItemIterator it = chest.Iterator(ItemType.ANY); ItemIterator it = chest.Iterator(ItemType.ANY);
while (it.hasNext()) { while (it.hasNext()) {
System.out.println(it.next()); System.out.println(it.next());
} }
} }
} }

View File

@ -7,24 +7,24 @@ package com.iluwatar.iterator;
*/ */
public class Item { public class Item {
private ItemType type; private ItemType type;
private String name; private String name;
public Item(ItemType type, String name) { public Item(ItemType type, String name) {
this.setType(type); this.setType(type);
this.name = name; this.name = name;
} }
@Override @Override
public String toString() { public String toString() {
return name; return name;
} }
public ItemType getType() { public ItemType getType() {
return type; return type;
} }
public void setType(ItemType type) { public void setType(ItemType type) {
this.type = type; this.type = type;
} }
} }

View File

@ -7,7 +7,7 @@ package com.iluwatar.iterator;
*/ */
public interface ItemIterator { public interface ItemIterator {
boolean hasNext(); boolean hasNext();
Item next(); Item next();
} }

View File

@ -7,6 +7,6 @@ package com.iluwatar.iterator;
*/ */
public enum ItemType { public enum ItemType {
ANY, WEAPON, RING, POTION ANY, WEAPON, RING, POTION
} }

View File

@ -10,30 +10,30 @@ import java.util.List;
*/ */
public class TreasureChest { public class TreasureChest {
private List<Item> items; private List<Item> items;
public TreasureChest() { public TreasureChest() {
items = new ArrayList<>(); items = new ArrayList<>();
items.add(new Item(ItemType.POTION, "Potion of courage")); items.add(new Item(ItemType.POTION, "Potion of courage"));
items.add(new Item(ItemType.RING, "Ring of shadows")); items.add(new Item(ItemType.RING, "Ring of shadows"));
items.add(new Item(ItemType.POTION, "Potion of wisdom")); items.add(new Item(ItemType.POTION, "Potion of wisdom"));
items.add(new Item(ItemType.POTION, "Potion of blood")); items.add(new Item(ItemType.POTION, "Potion of blood"));
items.add(new Item(ItemType.WEAPON, "Sword of silver +1")); items.add(new Item(ItemType.WEAPON, "Sword of silver +1"));
items.add(new Item(ItemType.POTION, "Potion of rust")); items.add(new Item(ItemType.POTION, "Potion of rust"));
items.add(new Item(ItemType.POTION, "Potion of healing")); items.add(new Item(ItemType.POTION, "Potion of healing"));
items.add(new Item(ItemType.RING, "Ring of armor")); items.add(new Item(ItemType.RING, "Ring of armor"));
items.add(new Item(ItemType.WEAPON, "Steel halberd")); items.add(new Item(ItemType.WEAPON, "Steel halberd"));
items.add(new Item(ItemType.WEAPON, "Dagger of poison")); items.add(new Item(ItemType.WEAPON, "Dagger of poison"));
} }
ItemIterator Iterator(ItemType type) { ItemIterator Iterator(ItemType type) {
return new TreasureChestItemIterator(this, type); return new TreasureChestItemIterator(this, type);
} }
public List<Item> getItems() { public List<Item> getItems() {
ArrayList<Item> list = new ArrayList<>(); ArrayList<Item> list = new ArrayList<>();
list.addAll(items); list.addAll(items);
return list; return list;
} }
} }

Some files were not shown because too many files have changed in this diff Show More