COMP2511 Week 4
Agenda
- Admin Stuff
- Law of Demeter
- Liskov Substitution Principle
- Streams and Lambda
- Design by Contract
Admin Stuff
-
Assignment 1 is due this Friday
- Make sure to push your code to the master branch
- Put a submission tag on it
- There is an assignment viva (discussion with me) after it's due in week 5/7.
- Get feedback on assignment UML, I'm happy to go through it in our lab or through email.
-
Assignment 2 finding a pair
- If I didn't ask you for your buddy last week or you don't know what I'm talking about, talk to me after class.
Law of Demeter
"Principle of least knowledge"
Law of Demeter
What is it?
Law of Demeter
What is it?
Law of Demeter (aka principle of least knowledge) is a design guideline that says that an object should assume as little as possible knowledge about the structures or properties of other objects.
It aims to achieve loose coupling in code.

Law of Demeter
What does this actually mean?
A method in an object should only call methods of:
- The object itself
- The object passed in as a parameter to the method
- Objects instantiated within the method
Only talk to your immediate friends
E.g. Don't do this!
o.get(name).get(thing).remove(node)
Code Review
In the unsw.training
package there is some skeleton code for a training system.
- Every employee must attend a whole day training seminar run by a qualified trainer
- Each trainer is running multiple seminars with no more than 10 attendees per seminar
In the TrainingSystem
class, there is a method to book a seminar for an employee given the dates on which they are available. This method violates the principle of least knowledge (Law of Demeter).
public class TrainingSystem {
private List<Trainer> trainers;
public LocalDate bookTraining(String employee, List<LocalDate> availability) {
for (Trainer trainer : trainers) {
for (Seminar seminar : trainer.getSeminars()) {
for (LocalDate available : availability) {
if (seminar.getStart().equals(available) &&
seminar.getAttendees().size() < 10) {
seminar.getAttendees().add(employee);
return available;
}
}
}
}
return null;
}
}
/**
* A trainer that runs in person seminars.
*/
public class Trainer {
private String name;
private String room;
private List<Seminar> seminars;
public List<Seminar> getSeminars() {
return seminars;
}
}
/**
* An in person all day seminar with
* a maximum of 10 attendees.
*/
public class Seminar {
private LocalDate start;
private List<String> attendees;
public LocalDate getStart() {
return start;
}
public List<String> getAttendees() {
return attendees;
}
}
/**
* An online seminar is a video that can be
* viewed at any time by employees. A record
* is kept of which employees have watched
* the seminar.
*/
public class OnlineSeminar extends Seminar {
private String videoURL;
private List<String> watched;
}
What line is law of demeter broken on?
Code Review
What other properties of this design are not desirable?
Code Review
What other properties of this design are not desirable?
- The design is needlessly tightly coupled as
TrainingSystem
is dependent on bothTrainer
andSeminar
-
TrainingSystem
suffers from low cohesion as any change to the system requires a change to this class. - The
Seminar
class has no control over the number of attendees. It relies onTrainingSystem
to ensure there are never more than 10. This makesSeminar
hard to re-use.
public class TrainingSystem {
public List<Trainer> trainers;
public LocalDate bookTraining(String employee, List<LocalDate> availability) {
for (Trainer trainer : trainers) {
LocalDate booked = trainer.book(employee, availability);
if (booked != null)
return booked;
}
return null;
}
}
/**
* A trainer that runs in person seminars.
*/
public class Trainer {
private String name;
private String room;
private List<Seminar> seminars;
public List<Seminar> getSeminars() {
return seminars;
}
public LocalDate book(String employee, List<LocalDate> availability) {
for (Seminar seminar : seminars) {
LocalDate booked = seminar.book(employee, availability);
if (booked != null)
return booked;
}
return null;
}
}
/**
* An in person all day seminar with a maximum of 10 attendees.
*/
public class Seminar {
private LocalDate start;
private List<String> attendees;
public LocalDate getStart() {
return start;
}
public LocalDate book(String employee, List<LocalDate> availability) {
for (LocalDate available : availability) {
if (start.equals(available) &&
attendees.size() < 10) {
attendees.add(employee);
return available;
}
}
return null;
}
}
/**
* An online seminar is a video
* that can be viewed at any time by employees.
* A record is kept of which employees have
* watched the seminar.
*/
public class OnlineSeminar extends Seminar {
private String videoURL;
private List<String> watched;
}
Liskov Substitution Principle (LSP)
Liskov Substitution Principle(LSP)
What is it?
Liskov Substitution Principle(LSP)
What is it?
Liskov Substitution Principle (LSP) states that objects of a superclass should be replaceable with objects of its subclasses without breaking the application.

Liskov Substitution Principle(LSP)
Where does OnlineSeminar violate LSP?
/**
* An in person all day seminar with
* a maximum of 10 attendees.
*/
public class Seminar {
private LocalDate start;
private List<String> attendees;
public LocalDate getStart() {
return start;
}
public List<String> getAttendees() {
return attendees;
}
}
/**
* An online seminar is a video that can
* be viewed at any time by employees.
* A record is kept of which employees
* have watched the seminar.
*/
public class OnlineSeminar extends Seminar {
private String videoURL;
private List<String> watched;
}
Liskov Substitution Principle(LSP)
Where does OnlineSeminar violate LSP?
-
OnlineSeminar
doesn't require a list of attendees
/**
* An in person all day seminar with
* a maximum of 10 attendees.
*/
public class Seminar {
private LocalDate start;
private List<String> attendees;
public LocalDate getStart() {
return start;
}
public List<String> getAttendees() {
return attendees;
}
}
/**
* An online seminar is a video that can
* be viewed at any time by employees.
* A record is kept of which employees
* have watched the seminar.
*/
public class OnlineSeminar extends Seminar {
private String videoURL;
private List<String> watched;
}
Streams and Lambda
Streams and Lambda
Streams abstract away the details of data structures and allows you to access all the values in the data structure through a common interface
Common uses of streams are:
- forEach
- filter
- map
- reduce
Streams and Lambda
Inside src/stream/App.java
, rewrite the following code using the .forEach()
method and a lambda.
List<String> strings = new ArrayList<String>(Arrays.asList(new String[] {"1", "2", "3", "4", "5"}));
for (String string : strings) {
System.out.println(string);
}
In the above example, discuss two different ways to write lambda expressions.
Streams and Lambda
- Rewrite the following code to use a stream and the map function.
- Modify your answer to use a scope operator instead of a normal lambda.
List<String> strings2 = new ArrayList<String>(Arrays.asList(new String[] {"1", "2", "3", "4", "5"}));
List<Integer> ints = new ArrayList<Integer>();
for (String string : strings2) {
ints.add(Integer.parseInt(string));
}
Design by Contract
What is it?
Design by Contract
What is it?
At the design time, responsibilities are clearly assigned to different software elements, clearly documented and enforced during the development using unit testing and/or language support.
- Clear distinction of responsibilities helps prevent redundant checks, resulting in simpler code and easier maintenance.
- Crashes if the required conditions are not satisfied! May not be suitable for high availability applications.
Design by Contract
Every software element should define a specification (or a contract) that govern its transaction with the rest of the software components.
A contract should address the following 3 conditions:
- Pre-condition - what does the contract expect?
- Post-condition - what does that contract guarantee?
- Invariant - What does the contract maintain?
Design by Contract
Design by Contract
public class Calculator {
public static Double add(Double a, Double b) {
return a + b;
}
public static Double subtract(Double a, Double b) {
return a - b;
}
public static Double multiply(Double a, Double b) {
return a * b;
}
public static Double divide(Double a, Double b) {
return a / b;
}
public static Double sin(Double angle) {
return Math.sin(angle);
}
public static Double cos(Double angle) {
return Math.cos(angle);
}
public static Double tan(Double angle) {
return Math.tan(angle);
}
}
public class Calculator {
/**
* @preconditions a, b != null
* @postconditions a + b
*/
public static Double add(Double a, Double b) {
return a + b;
}
/**
* @preconditions a, b != null
* @postconditions a - b
*/
public static Double subtract(Double a, Double b) {
return a - b;
}
/**
* @preconditions a, b != null
* @postconditions a * b
*/
public static Double multiply(Double a, Double b) {
return a * b;
}
/**
* @preconditions a, b != null, b != 0
* @postconditions a / b
*/
public static Double divide(Double a, Double b) {
return a / b;
}
/**
* @preconditions angle != null
* @postconditions sin(angle)
*/
public static Double sin(Double angle) {
return Math.sin(angle);
}
/**
* @preconditions angle != null
* @postconditions cos(angle)
*/
public static Double cos(Double angle) {
return Math.cos(angle);
}
/**
* @preconditions angle != null, angle != Math.PI / 2
* @postconditions tan(angle)
*/
public static Double tan(Double angle) {
return Math.tan(angle);
}
}
COMP2511 22T3 Week 4
By Jayden Leung
COMP2511 22T3 Week 4
- 112