"Principle of least knowledge"
What is it?
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.
What does this actually mean?
A method in an object should only call methods of:
Only talk to your immediate friends
E.g. Don't do this!
o.get(name).get(thing).remove(node)
In the unsw.training
package there is some skeleton code for a training system.
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?
What other properties of this design are not desirable?
What other properties of this design are not desirable?
TrainingSystem
is dependent on both Trainer
and Seminar
TrainingSystem
suffers from low cohesion as any change to the system requires a change to this class.Seminar
class has no control over the number of attendees. It relies on TrainingSystem
to ensure there are never more than 10. This makes Seminar
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;
}
What is it?
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.
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;
}
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 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:
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.
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));
}
What is it?
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.
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:
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);
}
}