diff --git a/java/src/main/java/com/elsevier/education/Exercise1.java b/java/src/main/java/com/elsevier/education/Exercise1.java index 90622840..737959ed 100644 --- a/java/src/main/java/com/elsevier/education/Exercise1.java +++ b/java/src/main/java/com/elsevier/education/Exercise1.java @@ -4,39 +4,43 @@ /** -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 variables. + +(Making the three instance variables final isn't strictly necessary, +but communicates that future developers shouldn't write methods which +mutate those variables.) */ 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 + +} 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 + } + } + +} diff --git a/java/src/main/java/com/elsevier/education/Exercise3.java b/java/src/main/java/com/elsevier/education/Exercise3.java index 6b208652..d55fb3d2 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 +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 +} diff --git a/java/src/main/java/com/elsevier/education/Exercise4.java b/java/src/main/java/com/elsevier/education/Exercise4.java index 87ffbc7a..07f15feb 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 "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 +"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 +} 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(); } }