From 74e4a8fbda390bfd6646c0603347f5e2e733df54 Mon Sep 17 00:00:00 2001 From: jtlong3rd Date: Tue, 28 Mar 2017 12:20:10 -0400 Subject: [PATCH 1/7] Complete Exercise 1 --- .../com/elsevier/education/Exercise1.java | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/java/src/main/java/com/elsevier/education/Exercise1.java b/java/src/main/java/com/elsevier/education/Exercise1.java index 90622840..d657a8ed 100644 --- a/java/src/main/java/com/elsevier/education/Exercise1.java +++ b/java/src/main/java/com/elsevier/education/Exercise1.java @@ -4,39 +4,40 @@ /** -TODO: Make this class immutable. +DONE: Make this class immutable. + +EXPLANATION: To force immutability, I removed the "setters" and +default constructor, made the three instance variables final, +and added a new constructor which receives the values of all +three instance values. */ public class Exercise1 { public static class Person { - - private Set phoneNumbers; - private String firstName; - private String lastName; - - public Person() { + + private final Set phoneNumbers; + private final String firstName; + private final String lastName; + + public Person(Set phoneNumbers, String firstName, String lastName) { + this.phoneNumbers = phoneNumbers; + this.firstName = firstName; + this.lastName = lastName; } public Set getPhoneNumbers() { return phoneNumbers; } - public void setPhoneNumbers(Set newPhoneNumbers) { - phoneNumbers = newPhoneNumbers; - } - + public String getFirstName() { return firstName; } - public void setFirstName(String newName) { - firstName = newName; - } - + public String getLastName() { return lastName; } - public void setLastName(String newName) { - lastName = newName; - } + } -} \ No newline at end of file + +} From f0c75d6607392a7dae029d4e5e41191482fdf6b2 Mon Sep 17 00:00:00 2001 From: jtlong3rd Date: Tue, 28 Mar 2017 12:31:49 -0400 Subject: [PATCH 2/7] Make addendum to Exercise 1 documentation --- java/src/main/java/com/elsevier/education/Exercise1.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/src/main/java/com/elsevier/education/Exercise1.java b/java/src/main/java/com/elsevier/education/Exercise1.java index d657a8ed..5dcf325b 100644 --- a/java/src/main/java/com/elsevier/education/Exercise1.java +++ b/java/src/main/java/com/elsevier/education/Exercise1.java @@ -11,6 +11,9 @@ and added a new constructor which receives the values of all three instance values. +(Making the three instance variables final isn't strictly necessary, +but communicates that future developers shouldn't write methods which +mutate those variable.) */ public class Exercise1 { From fb9754e4d6be007ef274d7cbeffdda54bfc77f9d Mon Sep 17 00:00:00 2001 From: jtlong3rd Date: Tue, 28 Mar 2017 12:32:10 -0400 Subject: [PATCH 3/7] Complete Exercise 2 --- .../com/elsevier/education/Exercise2.java | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/java/src/main/java/com/elsevier/education/Exercise2.java b/java/src/main/java/com/elsevier/education/Exercise2.java index b7b939e0..78280f33 100644 --- a/java/src/main/java/com/elsevier/education/Exercise2.java +++ b/java/src/main/java/com/elsevier/education/Exercise2.java @@ -2,28 +2,50 @@ /** -TODO refactor the Car to use dependency injection of the engine -TODO allow use of either a gas engine or electric engine (create an appropriate abstraction) -TODO make sure we have no-op implementations of the gas engine and electric engine +DONE: refactor the Car to use dependency injection of the engine +DONE: allow use of either a gas engine or electric engine (create an appropriate abstraction) +DONE: make sure we have no-op implementations of the gas engine and electric engine + +EXPLANATIONs: +1. There are several ways of incorporating a dependency injection. In the +interest of time, I've opted to do the simplest one, which is to make +a constructor which receives the engine instance variable (our "service") + +2. I opted to use an Engine interface with a spinWheels method, so as +to avoid potentially unnecessary inheritance (as would be the case if +I used an Engine abstract class instead) */ public class Exercise2 { public static class Car { - - private GasEngine engine = new GasEngine(); - - public Car() { + + private Engine engine; + + public Car(Engine engineService) { + engine = engineService; } - + public void moveForward() { engine.spinWheels(); } + + } + + public interface Engine { + public void spinWheels(); } - - public static class GasEngine { + + public static class GasEngine implements Engine { public void spinWheels() { // no-op for now } } -} \ No newline at end of file + + public static class ElectricEngine implements Engine { + public void spinWheels() { + // no-op for now + } + } + +} From fbeacd0ce591305f3dd48787c49b4db7a572bbf7 Mon Sep 17 00:00:00 2001 From: jtlong3rd Date: Tue, 28 Mar 2017 12:35:15 -0400 Subject: [PATCH 4/7] Complete Exercise 3 --- .../com/elsevier/education/Exercise3.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/java/src/main/java/com/elsevier/education/Exercise3.java b/java/src/main/java/com/elsevier/education/Exercise3.java index 6b208652..76d9d01b 100644 --- a/java/src/main/java/com/elsevier/education/Exercise3.java +++ b/java/src/main/java/com/elsevier/education/Exercise3.java @@ -4,28 +4,33 @@ /** -TODO Examine the failing test case for this class. +DONE: Examine the failing test case for this class. We should be able to call people.add() twice but end with only one object in it. We can test with "gradlew test" +EXPLANATION: The issue is that the ".hashCode" method is not compatible with +without the equals method: two "Persons" which are ".equal" to each +other should have the same hash code. The easiest fix is to have +the ".hashCode" be the id of the Person, as opposed to the id of the Person +times a random number. + */ public class Exercise3 { public static class Person { - - private static Random generator = new java.util.Random(); + private Integer id; - + public Person(int newId) { id = newId; } - + public int hashCode() { - return id * generator.nextInt(); + return id; } - + public boolean equals(Object other) { return id.equals(((Person)other).id); } } -} \ No newline at end of file +} From 7d87bdf0da55586f1b4a9c1f1b38e083ede5e685 Mon Sep 17 00:00:00 2001 From: jtlong3rd Date: Tue, 28 Mar 2017 12:38:17 -0400 Subject: [PATCH 5/7] Complete Exercise 4 --- .../com/elsevier/education/Exercise4.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/java/src/main/java/com/elsevier/education/Exercise4.java b/java/src/main/java/com/elsevier/education/Exercise4.java index 87ffbc7a..d8f5131e 100644 --- a/java/src/main/java/com/elsevier/education/Exercise4.java +++ b/java/src/main/java/com/elsevier/education/Exercise4.java @@ -2,26 +2,33 @@ /** -TODO Is Counter thread-safe? If so, why, and if not, how can we fix it? +DONE: Is Counter thread-safe? If so, why, and if not, how can we fix it? + +EXPLANATION: Counter is NOT thread-safe: because the "increment" method is not +atomic, a thread which is trying to "getCount" while another thread is "incrementing" +might return a stale value. + +One possible solution (among many!) is to make every method which uses the mutable +"count" instance variable synchronized. */ public class Exercise4 { public static class Counter { - + private int count = 0; - - public int increment() { + + public synchronized int increment() { return ++count; } - - public int getCount() { + + public synchronized int getCount() { return count; } - - public void resetCount() { + + public synchronized void resetCount() { count = 0; } } -} \ No newline at end of file +} From 543e48a6548c3e3dd5019da17eecfb4bc2389e13 Mon Sep 17 00:00:00 2001 From: jtlong3rd Date: Tue, 28 Mar 2017 12:42:39 -0400 Subject: [PATCH 6/7] Complete Exercise 5 --- .../com/elsevier/education/Exercise5.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/java/src/main/java/com/elsevier/education/Exercise5.java b/java/src/main/java/com/elsevier/education/Exercise5.java index abd81e3f..cd13b826 100644 --- a/java/src/main/java/com/elsevier/education/Exercise5.java +++ b/java/src/main/java/com/elsevier/education/Exercise5.java @@ -2,19 +2,33 @@ /** -TODO: Turn the "Singleton" class into an actual singleton. The main() method should still call .doSomething(). +DONE: Turn the "Singleton" class into an actual singleton. The main() method should still call .doSomething(). + +EXPLANATION: This is a standard design pattern. I add a private static final variable +which refers to the Singleton instance, a private default constructor for creating this +instance, and a public static method which "gets" (returns) the instance. */ public class Exercise5 { - + public static class Singleton { + private static final Singleton instance = new Singleton(); + + private Singleton() { + // no-op (for now!) + } + + public static Singleton getInstance() { + return instance; + } + public void doSomething() { System.out.println("Doing something...."); - } + } } - + public static void main(String a[]){ - Singleton st = new Singleton(); - st.doSomeThing(); + Singleton st = Singleton.getInstance(); + st.doSomething(); } } From 2585142b4fde00425a855339389dc27d6c2fa53a Mon Sep 17 00:00:00 2001 From: jtlong3rd Date: Tue, 28 Mar 2017 12:52:00 -0400 Subject: [PATCH 7/7] Make minor edits to Exercises 1, 3, and 4 documentation --- java/src/main/java/com/elsevier/education/Exercise1.java | 4 ++-- java/src/main/java/com/elsevier/education/Exercise3.java | 2 +- java/src/main/java/com/elsevier/education/Exercise4.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/src/main/java/com/elsevier/education/Exercise1.java b/java/src/main/java/com/elsevier/education/Exercise1.java index 5dcf325b..737959ed 100644 --- a/java/src/main/java/com/elsevier/education/Exercise1.java +++ b/java/src/main/java/com/elsevier/education/Exercise1.java @@ -9,11 +9,11 @@ EXPLANATION: To force immutability, I removed the "setters" and default constructor, made the three instance variables final, and added a new constructor which receives the values of all -three instance values. +three instance variables. (Making the three instance variables final isn't strictly necessary, but communicates that future developers shouldn't write methods which -mutate those variable.) +mutate those variables.) */ public class Exercise1 { diff --git a/java/src/main/java/com/elsevier/education/Exercise3.java b/java/src/main/java/com/elsevier/education/Exercise3.java index 76d9d01b..d55fb3d2 100644 --- a/java/src/main/java/com/elsevier/education/Exercise3.java +++ b/java/src/main/java/com/elsevier/education/Exercise3.java @@ -9,7 +9,7 @@ We can test with "gradlew test" EXPLANATION: The issue is that the ".hashCode" method is not compatible with -without the equals method: two "Persons" which are ".equal" to each +the equals method: two "Persons" which are ".equal" to each other should have the same hash code. The easiest fix is to have the ".hashCode" be the id of the Person, as opposed to the id of the Person times a random number. diff --git a/java/src/main/java/com/elsevier/education/Exercise4.java b/java/src/main/java/com/elsevier/education/Exercise4.java index d8f5131e..07f15feb 100644 --- a/java/src/main/java/com/elsevier/education/Exercise4.java +++ b/java/src/main/java/com/elsevier/education/Exercise4.java @@ -5,7 +5,7 @@ DONE: Is Counter thread-safe? If so, why, and if not, how can we fix it? EXPLANATION: Counter is NOT thread-safe: because the "increment" method is not -atomic, a thread which is trying to "getCount" while another thread is "incrementing" +atomic, a thread which is "getCount"ing while another thread is "increment"ing might return a stale value. One possible solution (among many!) is to make every method which uses the mutable