From 753ee91bb641c24f7e154f54c5a9b35e5b25b502 Mon Sep 17 00:00:00 2001
From: Colin DAMON <cdamon@ippon.fr>
Date: Fri, 29 Jan 2021 19:40:41 +0100
Subject: [PATCH] Kata resolution

---
 .../java/fr/ippon/rental/ChildrensMovie.java  | 16 +++++
 .../java/fr/ippon/rental/ConsoleRenderer.java | 26 ++++++++
 .../main/java/fr/ippon/rental/Customer.java   | 63 +++++++------------
 .../java/fr/ippon/rental/HtmlRenderer.java    | 26 ++++++++
 .../src/main/java/fr/ippon/rental/Movie.java  | 26 +++-----
 .../src/main/java/fr/ippon/rental/Movies.java | 16 +++++
 .../java/fr/ippon/rental/NewReleaseMovie.java | 17 +++++
 .../java/fr/ippon/rental/RegularMovie.java    | 16 +++++
 .../main/java/fr/ippon/rental/Renderer.java   |  9 +++
 .../src/main/java/fr/ippon/rental/Rental.java | 24 +++++--
 .../java/fr/ippon/rental/CustomerTest.java    | 43 ++++++++++---
 11 files changed, 209 insertions(+), 73 deletions(-)
 create mode 100644 movie-rental/src/main/java/fr/ippon/rental/ChildrensMovie.java
 create mode 100644 movie-rental/src/main/java/fr/ippon/rental/ConsoleRenderer.java
 create mode 100644 movie-rental/src/main/java/fr/ippon/rental/HtmlRenderer.java
 create mode 100644 movie-rental/src/main/java/fr/ippon/rental/Movies.java
 create mode 100644 movie-rental/src/main/java/fr/ippon/rental/NewReleaseMovie.java
 create mode 100644 movie-rental/src/main/java/fr/ippon/rental/RegularMovie.java
 create mode 100644 movie-rental/src/main/java/fr/ippon/rental/Renderer.java

diff --git a/movie-rental/src/main/java/fr/ippon/rental/ChildrensMovie.java b/movie-rental/src/main/java/fr/ippon/rental/ChildrensMovie.java
new file mode 100644
index 00000000..e22bc1e1
--- /dev/null
+++ b/movie-rental/src/main/java/fr/ippon/rental/ChildrensMovie.java
@@ -0,0 +1,16 @@
+package fr.ippon.rental;
+
+public class ChildrensMovie extends Movie {
+
+  public ChildrensMovie(String title) {
+    super(title);
+  }
+
+  public double getAmount(int daysRented) {
+    if (daysRented > 3) {
+      return 1.5 + (daysRented - 3) * 1.5;
+    }
+
+    return 1.5;
+  }
+}
diff --git a/movie-rental/src/main/java/fr/ippon/rental/ConsoleRenderer.java b/movie-rental/src/main/java/fr/ippon/rental/ConsoleRenderer.java
new file mode 100644
index 00000000..2417fb2d
--- /dev/null
+++ b/movie-rental/src/main/java/fr/ippon/rental/ConsoleRenderer.java
@@ -0,0 +1,26 @@
+package fr.ippon.rental;
+
+public class ConsoleRenderer implements Renderer {
+
+  @Override
+  public String header(String name) {
+    return "Rental Record for " + name + "\n";
+  }
+
+  @Override
+  public String movie(Rental rental, double amount) {
+    return "\t" + rental.getMovie().getTitle() + "\t" + String.valueOf(amount) + "\n";
+  }
+
+  @Override
+  public String footer(double totalAmount, int frequentRenterPoints) {
+    return new StringBuilder()
+      .append("Amount owed is ")
+      .append(totalAmount)
+      .append("\n")
+      .append("You earned ")
+      .append(frequentRenterPoints)
+      .append(" frequent renter points")
+      .toString();
+  }
+}
diff --git a/movie-rental/src/main/java/fr/ippon/rental/Customer.java b/movie-rental/src/main/java/fr/ippon/rental/Customer.java
index bfe16efc..39fc4e02 100644
--- a/movie-rental/src/main/java/fr/ippon/rental/Customer.java
+++ b/movie-rental/src/main/java/fr/ippon/rental/Customer.java
@@ -4,59 +4,42 @@ import java.util.ArrayList;
 import java.util.List;
 
 public class Customer {
-  private String _name;
-  private List<Rental> _rentals = new ArrayList<Rental>();
+  private final String name;
+  private final List<Rental> rentals = new ArrayList<Rental>();
 
   public Customer(String name) {
-    _name = name;
+    this.name = name;
   }
 
   public void addRental(Rental arg) {
-    _rentals.add(arg);
+    rentals.add(arg);
   }
 
   public String getName() {
-    return _name;
+    return name;
   }
 
-  public String statement() {
+  public String statement(Renderer renderer) {
+    StringBuilder result = new StringBuilder(renderer.header(name));
+
     double totalAmount = 0;
-    int frequentRenterPoints = 0;
-    String result = "Rental Record for " + getName() + "\n";
-
-    for (Rental each : _rentals) {
-      double thisAmount = 0;
-
-      //determine amounts for each line
-      switch (each.getMovie().getPriceCode()) {
-        case Movie.REGULAR:
-          thisAmount += 2;
-          if (each.getDaysRented() > 2) thisAmount += (each.getDaysRented() - 2) * 1.5;
-          break;
-        case Movie.NEW_RELEASE:
-          thisAmount += each.getDaysRented() * 3;
-          break;
-        case Movie.CHILDRENS:
-          thisAmount += 1.5;
-          if (each.getDaysRented() > 3) thisAmount += (each.getDaysRented() - 3) * 1.5;
-          break;
-      }
-
-      // add frequent renter points
-      frequentRenterPoints++;
-
-      // add bonus for a two day new release rental
-      if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) frequentRenterPoints++;
-
-      // show figures for this rental
-      result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmount) + "\n";
-      totalAmount += thisAmount;
+    for (Rental rental : rentals) {
+      double amount = calculateAmount(rental);
+
+      result.append(renderer.movie(rental, amount));
+      totalAmount += amount;
     }
 
-    // add footer lines
-    result += "Amount owed is " + String.valueOf(totalAmount) + "\n";
-    result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points";
+    result.append(renderer.footer(totalAmount, calculateFrequentRenterPoints()));
+
+    return result.toString();
+  }
+
+  private int calculateFrequentRenterPoints() {
+    return rentals.stream().mapToInt(Rental::getRenterPoints).sum();
+  }
 
-    return result;
+  private double calculateAmount(Rental rental) {
+    return rental.amount();
   }
 }
diff --git a/movie-rental/src/main/java/fr/ippon/rental/HtmlRenderer.java b/movie-rental/src/main/java/fr/ippon/rental/HtmlRenderer.java
new file mode 100644
index 00000000..71e69168
--- /dev/null
+++ b/movie-rental/src/main/java/fr/ippon/rental/HtmlRenderer.java
@@ -0,0 +1,26 @@
+package fr.ippon.rental;
+
+public class HtmlRenderer implements Renderer {
+
+  @Override
+  public String header(String name) {
+    return "<h1>Rental Record for " + name + "</h1>\n<table>";
+  }
+
+  @Override
+  public String movie(Rental rental, double amount) {
+    return "<tr><td>" + rental.getMovie().getTitle() + "</td><td>" + String.valueOf(amount) + "</td></tr>\n";
+  }
+
+  @Override
+  public String footer(double totalAmount, int frequentRenterPoints) {
+    return new StringBuilder()
+      .append("</table><p>Amount owed is <em>")
+      .append(totalAmount)
+      .append("</em></p>\n")
+      .append("<p>You earned <em>")
+      .append(frequentRenterPoints)
+      .append("</em> frequent renter points</p>")
+      .toString();
+  }
+}
diff --git a/movie-rental/src/main/java/fr/ippon/rental/Movie.java b/movie-rental/src/main/java/fr/ippon/rental/Movie.java
index 6727cb4b..e545ba30 100644
--- a/movie-rental/src/main/java/fr/ippon/rental/Movie.java
+++ b/movie-rental/src/main/java/fr/ippon/rental/Movie.java
@@ -1,27 +1,19 @@
 package fr.ippon.rental;
 
-public class Movie {
-  public static final int CHILDRENS = 2;
-  public static final int NEW_RELEASE = 1;
-  public static final int REGULAR = 0;
+public abstract class Movie {
+  private final String title;
 
-  private String _title;
-  private int _priceCode;
-
-  public Movie(String title, int priceCode) {
-    _title = title;
-    _priceCode = priceCode;
+  public Movie(String title) {
+    this.title = title;
   }
 
-  public int getPriceCode() {
-    return _priceCode;
+  public String getTitle() {
+    return title;
   }
 
-  public void setPriceCode(int arg) {
-    _priceCode = arg;
-  }
+  public abstract double getAmount(int daysRented);
 
-  public String getTitle() {
-    return _title;
+  public boolean isNewRelease() {
+    return false;
   }
 }
diff --git a/movie-rental/src/main/java/fr/ippon/rental/Movies.java b/movie-rental/src/main/java/fr/ippon/rental/Movies.java
new file mode 100644
index 00000000..b9767585
--- /dev/null
+++ b/movie-rental/src/main/java/fr/ippon/rental/Movies.java
@@ -0,0 +1,16 @@
+package fr.ippon.rental;
+
+public class Movies {
+
+  public static Movie regular(String title) {
+    return new RegularMovie(title);
+  }
+
+  public static Movie newRelease(String title) {
+    return new NewReleaseMovie(title);
+  }
+
+  public static Movie childrens(String title) {
+    return new ChildrensMovie(title);
+  }
+}
diff --git a/movie-rental/src/main/java/fr/ippon/rental/NewReleaseMovie.java b/movie-rental/src/main/java/fr/ippon/rental/NewReleaseMovie.java
new file mode 100644
index 00000000..6f3e6c0d
--- /dev/null
+++ b/movie-rental/src/main/java/fr/ippon/rental/NewReleaseMovie.java
@@ -0,0 +1,17 @@
+package fr.ippon.rental;
+
+public class NewReleaseMovie extends Movie {
+
+  public NewReleaseMovie(String title) {
+    super(title);
+  }
+
+  public double getAmount(int daysRented) {
+    return daysRented * 3;
+  }
+
+  @Override
+  public boolean isNewRelease() {
+    return true;
+  }
+}
diff --git a/movie-rental/src/main/java/fr/ippon/rental/RegularMovie.java b/movie-rental/src/main/java/fr/ippon/rental/RegularMovie.java
new file mode 100644
index 00000000..1db4e079
--- /dev/null
+++ b/movie-rental/src/main/java/fr/ippon/rental/RegularMovie.java
@@ -0,0 +1,16 @@
+package fr.ippon.rental;
+
+public class RegularMovie extends Movie {
+
+  public RegularMovie(String title) {
+    super(title);
+  }
+
+  public double getAmount(int daysRented) {
+    if (daysRented > 2) {
+      return 2 + (daysRented - 2) * 1.5;
+    }
+
+    return 2;
+  }
+}
diff --git a/movie-rental/src/main/java/fr/ippon/rental/Renderer.java b/movie-rental/src/main/java/fr/ippon/rental/Renderer.java
new file mode 100644
index 00000000..28898108
--- /dev/null
+++ b/movie-rental/src/main/java/fr/ippon/rental/Renderer.java
@@ -0,0 +1,9 @@
+package fr.ippon.rental;
+
+public interface Renderer {
+  String header(String name);
+
+  String movie(Rental rental, double amount);
+
+  String footer(double totalAmount, int frequentRenterPoints);
+}
diff --git a/movie-rental/src/main/java/fr/ippon/rental/Rental.java b/movie-rental/src/main/java/fr/ippon/rental/Rental.java
index d0188617..b7938892 100644
--- a/movie-rental/src/main/java/fr/ippon/rental/Rental.java
+++ b/movie-rental/src/main/java/fr/ippon/rental/Rental.java
@@ -4,19 +4,31 @@ package fr.ippon.rental;
  * The rental class represents a customer renting a movie.
  */
 public class Rental {
-  private Movie _movie;
-  private int _daysRented;
+  private final Movie movie;
+  private final int daysRented;
 
   public Rental(Movie movie, int daysRented) {
-    _movie = movie;
-    _daysRented = daysRented;
+    this.movie = movie;
+    this.daysRented = daysRented;
   }
 
   public int getDaysRented() {
-    return _daysRented;
+    return daysRented;
   }
 
   public Movie getMovie() {
-    return _movie;
+    return movie;
+  }
+
+  public int getRenterPoints() {
+    if (movie.isNewRelease() && daysRented > 1) {
+      return 2;
+    }
+
+    return 1;
+  }
+
+  public double amount() {
+    return movie.getAmount(daysRented);
   }
 }
diff --git a/movie-rental/src/test/java/fr/ippon/rental/CustomerTest.java b/movie-rental/src/test/java/fr/ippon/rental/CustomerTest.java
index ca193508..7b78d858 100644
--- a/movie-rental/src/test/java/fr/ippon/rental/CustomerTest.java
+++ b/movie-rental/src/test/java/fr/ippon/rental/CustomerTest.java
@@ -1,5 +1,6 @@
 package fr.ippon.rental;
 
+import static fr.ippon.rental.Movies.*;
 import static org.assertj.core.api.Assertions.*;
 
 import org.junit.jupiter.api.Test;
@@ -7,15 +8,7 @@ import org.junit.jupiter.api.Test;
 public class CustomerTest {
 
   @Test
-  public void test() {
-    Customer customer = new Customer("Bob");
-    customer.addRental(new Rental(new Movie("Jaws", Movie.REGULAR), 2));
-    customer.addRental(new Rental(new Movie("Golden Eye", Movie.REGULAR), 3));
-    customer.addRental(new Rental(new Movie("Short New", Movie.NEW_RELEASE), 1));
-    customer.addRental(new Rental(new Movie("Long New", Movie.NEW_RELEASE), 2));
-    customer.addRental(new Rental(new Movie("Bambi", Movie.CHILDRENS), 3));
-    customer.addRental(new Rental(new Movie("Toy Story", Movie.CHILDRENS), 4));
-
+  public void shouldRenderConsole() {
     String expected =
       "" +
       "Rental Record for Bob\n" +
@@ -28,6 +21,36 @@ public class CustomerTest {
       "Amount owed is 19.0\n" +
       "You earned 7 frequent renter points";
 
-    assertThat(customer.statement()).isEqualTo(expected);
+    assertThat(customer().statement(new ConsoleRenderer())).isEqualTo(expected);
+  }
+
+  @Test
+  void shouldRenderHtml() {
+    String expected =
+      "" +
+      "<h1>Rental Record for Bob</h1>\n" +
+      "<table>" +
+      "<tr><td>Jaws</td><td>2.0</td></tr>\n" +
+      "<tr><td>Golden Eye</td><td>3.5</td></tr>\n" +
+      "<tr><td>Short New</td><td>3.0</td></tr>\n" +
+      "<tr><td>Long New</td><td>6.0</td></tr>\n" +
+      "<tr><td>Bambi</td><td>1.5</td></tr>\n" +
+      "<tr><td>Toy Story</td><td>3.0</td></tr>\n" +
+      "</table>" +
+      "<p>Amount owed is <em>19.0</em></p>\n" +
+      "<p>You earned <em>7</em> frequent renter points</p>";
+
+    assertThat(customer().statement(new HtmlRenderer())).isEqualTo(expected);
+  }
+
+  private Customer customer() {
+    Customer customer = new Customer("Bob");
+    customer.addRental(new Rental(regular("Jaws"), 2));
+    customer.addRental(new Rental(regular("Golden Eye"), 3));
+    customer.addRental(new Rental(newRelease("Short New"), 1));
+    customer.addRental(new Rental(newRelease("Long New"), 2));
+    customer.addRental(new Rental(childrens("Bambi"), 3));
+    customer.addRental(new Rental(childrens("Toy Story"), 4));
+    return customer;
   }
 }
-- 
GitLab