diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/ComparatorStrategy.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/ComparatorStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..190b583645f973150ecf412fd93d4b7862195c66 --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/ComparatorStrategy.java @@ -0,0 +1,74 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; + +public class ComparatorStrategy { + + public static void main(String[] args) { + List<Integer> values = Arrays.asList(3, 5, 7, 2, 1, 1, 2, 7, 8, 8, 9); + Comparator<Integer> strategy = + Comparator.<Integer>comparingInt(x -> x % 2).thenComparing(Function.identity()).reversed(); + Collections.sort(values, strategy); + System.out.println(values); + + removeDuplicates(List.of("a", "A", "b"), String::equalsIgnoreCase); + removeDuplicates(List.of("a", "A", "b"), String::equals); + } + + interface EqualsTest { + boolean isEqual(String s, String t); + } + + private static List<String> removeDuplicates(List<String> input, EqualsTest test) { + ArrayList<String> result = new ArrayList<>(); + for (String s : input) { + boolean found = false; + for (String r : result) { + if (test.isEqual(s, r)) { + found = true; + } + } + if (!found) { + result.add(s); + } + } + return result; + } + + private static List<String> removeDuplicatesIgnoringCase(List<String> input) { + ArrayList<String> result = new ArrayList<>(); + for (String s : input) { + boolean found = false; + for (String r : result) { + if (s.equalsIgnoreCase(r)) { + found = true; + } + } + if (!found) { + result.add(s); + } + } + return result; + } + + private static List<String> removeDuplicatesExactMatch(List<String> input) { + ArrayList<String> result = new ArrayList<>(); + for (String s : input) { + boolean found = false; + for (String r : result) { + if (s.equals(r)) { + found = true; + } + } + if (!found) { + result.add(s); + } + } + return result; + } +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/DvdCompositePattern.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/DvdCompositePattern.java new file mode 100644 index 0000000000000000000000000000000000000000..eafa0f928717b902eb0afd7a83c1d87084f31fef --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/DvdCompositePattern.java @@ -0,0 +1,78 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +interface Watchable { + int priceInPence(); + + String title(); +} + +class Dvd implements Watchable { + private final String title; + private final int priceInPence; + + Dvd(String title, int priceInPence) { + this.title = title; + this.priceInPence = priceInPence; + } + + @Override + public int priceInPence() { + return priceInPence; + } + + @Override + public String title() { + return title; + } + + @Override + public String toString() { + return String.format("%d: %s%n", priceInPence(), title()); + } +} + +class BoxSet implements Watchable { + + private final List<Watchable> items; + + BoxSet(List<Watchable> items) { + this.items = List.copyOf(items); + } + + BoxSet(Watchable... items) { + this.items = List.copyOf(Arrays.asList(items)); + } + + @Override + public int priceInPence() { + return (int) (items.stream().mapToInt(Watchable::priceInPence).sum() * 0.9); + } + + @Override + public String title() { + return items.stream().map(Watchable::title).collect(Collectors.joining(", ")); + } + + @Override + public String toString() { + return String.format("%d: %s%n", priceInPence(), title()); + } +} + +public class DvdCompositePattern { + public static void main(String[] args) { + Dvd m1 = new Dvd("Episode IV: A New Hope", 100); + Dvd m2 = new Dvd("Episode V: The Empire Strikes Back", 100); + Dvd m3 = new Dvd("Episode VI: Return of the Jedi", 100); + BoxSet b1 = new BoxSet(m1, m2, m3); + Dvd m4 = new Dvd("Episode I: The Phantom Menace", 5); + Dvd m5 = new Dvd("Episode II: Attack of the Clones", 5); + Dvd m6 = new Dvd("Episode III: Revenge of the Sith", 5); + BoxSet b2 = new BoxSet(m4, m5, m6); + BoxSet all = new BoxSet(b1, b2); + } +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/Factory.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/Factory.java new file mode 100644 index 0000000000000000000000000000000000000000..2ad00b3990a653496a34561da4595f65b7e573fb --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/Factory.java @@ -0,0 +1,44 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +import java.util.HashMap; +import java.util.Map; + +public class Factory { + + private Map<String, Integer> used = new HashMap<>(); + private int counter = 0; + + static class SpecialThing { + + private final String name; + private final int id; + + private SpecialThing(String name, int id) { + this.name = name; + this.id = id; + } + } + + class AnotherOne { + + AnotherOne() { + counter++; + } + } + + public SpecialThing newSpecialThing(String name) { + if (!used.containsKey(name)) { + used.put(name, counter++); + } + return new SpecialThing(name, used.get(name)); + } + + public static void main(String[] args) { + + Factory factory1 = new Factory(); + Factory factory2 = new Factory(); + + SpecialThing one = factory1.newSpecialThing("apple"); + SpecialThing two = factory2.newSpecialThing("orange"); + } +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithEnum.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..6e8d3aa3c8e4747a68ed449f18c8e8d2193ae527 --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithEnum.java @@ -0,0 +1,51 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +/** + * Model a desk fan with three settings: off, slow and fast. + * + * <p>The fan has one button to click through these three settings. + * + * <p>The two methods on this class are called by the firmware of the fan. {@code click} is called + * whenever someone presses the button to change setting. {@code update} is called whenever the + * motor is ready to change speed. + */ +public class FanSpeedWithEnum { + + enum Speed { + OFF, + SLOW, + FAST + } + + private Speed state; + + /** Set the motor turning at the correct speed. */ + void update(MotorController motorController) { + switch (state) { + case OFF: + motorController.stop(); + break; + case SLOW: + motorController.turnSlow(); + break; + case FAST: + motorController.turnFast(); + break; + } + } + + /** Respond to a button click to change between settings. */ + void click() { + switch (state){ + case OFF: + state = Speed.SLOW; + break; + case SLOW: + state = Speed.FAST; + break; + case FAST: + state = Speed.OFF; + break; + } + } +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithInts.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithInts.java new file mode 100644 index 0000000000000000000000000000000000000000..8439bef8a64156d165705f0840091d58e73c2e66 --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithInts.java @@ -0,0 +1,47 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +/** + * Model a desk fan with three settings: off, slow and fast. + * + * <p>The fan has one button to click through these three settings. + * + * <p>The two methods on this class are called by the firmware of the fan. {@code click} is called + * whenever someone presses the button to change setting. {@code update} is called whenever the + * motor is ready to change speed. + */ +public class FanSpeedWithInts { + + private static final int OFF = 0; + private static final int SLOW = 1; + private static final int FAST = 2; + + private int state = OFF; + + /** Set the motor turning at the correct speed. */ + void update(MotorController motorController) { + switch (state) { + case OFF: + motorController.stop(); + return; + case SLOW: + motorController.turnSlow(); + return; + case FAST: + motorController.turnFast(); + } + } + + /** Respond to a button click to change between settings. */ + void click() { + switch (state) { + case OFF: + state = SLOW; + return; + case SLOW: + state = FAST; + return; + case FAST: + state = OFF; + } + } +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithStatePattern.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithStatePattern.java new file mode 100644 index 0000000000000000000000000000000000000000..ae4d5d2b6ea45725cf0f78269a9c3e24c2c7d6d8 --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/FanSpeedWithStatePattern.java @@ -0,0 +1,69 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +/** + * Model a desk fan with three settings: off, slow and fast. + * + * <p>The fan has one button to click through these three settings. + * + * <p>The two methods on this class are called by the firmware of the fan. {@code click} is called + * whenever someone presses the button to change setting. {@code update} is called whenever the + * motor is ready to change speed. + */ +public class FanSpeedWithStatePattern { + + interface FanState { + void update(MotorController motorController); + + void click(); + } + + class Stop implements FanState { + @Override + public void update(MotorController motorController) { + motorController.stop(); + } + + @Override + public void click() { + state = new Slow(); + } + } + + class Slow implements FanState { + + @Override + public void update(MotorController motorController) { + motorController.turnSlow(); + } + + @Override + public void click() { + state = new Fast(); + } + } + + class Fast implements FanState { + + @Override + public void update(MotorController motorController) { + motorController.turnFast(); + } + + @Override + public void click() { + state = new Stop(); + } + } + + private FanState state = new Stop(); + + /** Set the motor turning at the correct speed. */ + void update(MotorController motorController) { + state.update(motorController); + } + + /** Respond to a button click to change between settings. */ + void click() { + state.click(); + } +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/LambdaRef.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/LambdaRef.java new file mode 100644 index 0000000000000000000000000000000000000000..96f2da246daa06c6df2c047ce019f2b92c0a4438 --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/LambdaRef.java @@ -0,0 +1,36 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +import java.util.List; +import java.util.stream.Collectors; + +class Doubler { + + int dbl(int x) { + return x * 2; + } +} + +class StaticOrNot { + + int x; + + int dbl() { + return this.x * 2; + } + + static int dbl2(StaticOrNot thiss) { + return thiss.x * 2; + } +} + +public class LambdaRef { + + public static void main(String[] args) { + List<Integer> ints = List.of(1, 2, 3, 4, 5, 6); + Doubler dd = new Doubler(); + List<Integer> doubled = ints.stream().map(dd::dbl).collect(Collectors.toList()); + + List<String> strings = List.of("andy", "is", "here"); + List<String> upper = strings.stream().map(String::toUpperCase).collect(Collectors.toList()); + } +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/MotorController.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/MotorController.java new file mode 100644 index 0000000000000000000000000000000000000000..cbc5dcc1eeea251d7a826228598bbcf691595944 --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/MotorController.java @@ -0,0 +1,10 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +class MotorController { + + void turnFast() {} + + void turnSlow() {} + + void stop() {} +} diff --git a/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/ObserverPattern.java b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/ObserverPattern.java new file mode 100644 index 0000000000000000000000000000000000000000..10111083de8619e9a641d50b8fab54396f9172c6 --- /dev/null +++ b/src/main/java/uk/ac/cam/acr31/oop/democode1920/lecture12/ObserverPattern.java @@ -0,0 +1,43 @@ +package uk.ac.cam.acr31.oop.democode1920.lecture12; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Font; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class ObserverPattern { + + public static void main(String[] args) { + + JFrame window = new JFrame(); + window.setSize(500, 500); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.setTitle("A very exciting GUI"); + + JLabel label = new JLabel("Hello", JLabel.CENTER); + window.add(label, BorderLayout.CENTER); + label.setForeground(Color.RED); + label.setFont(new Font(label.getFont().getFontName(), Font.BOLD, 30)); + + JButton button = new JButton("Click me! Click me!"); + window.add(button, BorderLayout.SOUTH); + + // Important bit - you can do this as a lambda or an anonymous inner class or indeed anything + // that implements ActionListener + button.addActionListener( + e -> { + if (label.getText().equals("Hello")) { + label.setText("Goodbye"); + } else { + label.setText("Hello"); + } + }); + + // you can have as many as you like + button.addActionListener(e -> System.out.println("CLICKED!")); + + window.setVisible(true); + } +}