COMP2511 Tute04
Agenda
- Admin Stuff
- Law of Demeter
- SOLID principles
- Streams and Lambda
- Strategy Pattern
- Observer Pattern
Admin Stuff
- Assignment 1 is due next week
- Submissions are done via Gitlab, all you need to do is push to your main branch
- Pipelines slow down close to deadline so avoid making last minute pushes!
- Test your linting (easy marks) and do quick dryrun for sanity checks
Law of Demeter
"Principle of least knowledge"
Law of Demeter
What is it?
A method in an object should only call methods of:
- The object itself
- Attributes of the object
- Object passed in as a parameter to a method
- Objects instantiated within the method
Only talk to your immediate friends
Law of Demeter
Avoid doing method chaining! (You will lose marks)
o.get(name).get(thing).remove(node)Purpose?
Achieve loose coupling in code

Coupling and Cohesion
Cohesion refers to what a class / module can do.
Low cohesion means class has a great variety of actions (broad, unfocused)
High cohesion means a class is focused on what it should be doing
Cohesion
Coupling
Coupling refers to how dependent classes are toward each other.
High coupling makes it difficult to change your code as classes are so knit together.
Good software design is
high cohesion
and
low coupling
Law of Demeter
In the unsw.training package there is some 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).
Where and how is the Law of Demeter being violated?
TrainingSystem is getting instances of Seminar from instances of Trainer and calling its methods
Interacting with classes beyond its friends
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;
}Law of Demeter
In violating this principle, what other properties of this design is not desirable?
Law of Demeter
-
TrainingSystemis needlessly tightly coupled withTrainerandSeminar -
TrainingSystemhas low cohesion as it relies on classes that are not its closest friends to achieve its purpose -
Seminarhas no control over the number of attendees. It relies onTrainingSystemto restrict number of attendees. This makesSeminarhard to re-use in the future (poor encapsulation)
In violating this principle, what other properties of this design is not desirable?
Law of Demeter
- No longer tightly coupled.
TrainingSystemno longer has any knowledge ofSeminar. - Each class now has a clear purpose in booking a training seminar. Any behaviour that relates to them is now delegated to their classes.
- The
Seminarclass is responsible for ensuring number of attendees do no exceed 10.
In refactoring the principle is no longer violated, how has this affected other properties of the design?
Law of Demeter
Liskov Substitution Principle
How does OnlineSeminar violate LSP?
/**
* 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
How does OnlineSeminar violate LSP?
/**
* 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;
}
Does not have a list of attendees, so clients won't be able to use it in the same way as Seminar.
i.e making a booking
SOLID
SOLID
- Single Responsibility Principle
- Open/Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
SRP
- A class should only focus on a single functionality
OCP
- A class should be open for extension but closed for modification
ISP
- Favor many specific interfaces over a broader general one
DIP
- Depend on abstractions, not implementations
- Ease of maintenance
- Productivity
- Improved collaboration
- Slower rate of software deterioration
Streams and Lambda
Streams and Lambda
A pipeline contains:
- A source (i.e. collection, array, generator function)
- Intermediate operations which transforms a stream into another stream
What is a stream?
A sequence of elements which runs through the pipeline that transforms from intermediate operations.

Streams and Lambda
map(): Applies a given function to elements in the stream
filter(): Selects specific elements as per the Predicate (boolean function)
sorted(): Used to sort the stream
Intermediate Operations
collect(): Collects the result of a stream into a list, set, etc.
forEach(): Iterate through every element of the stream
reduce(): Reduce the elements of a stream into a single value
Terminal Operations
Strategy Pattern
Strategy Pattern
What is it?
Behavioural design pattern that lets you define a family of methods that are interchangeable at runtime
What problem does it solve?
Introducing new behaviours without modifying existing code, adhering to the Open-Closed Principle. Avoids conditional statements to select algorithms.
When should we use this pattern?
When we need multiple ways of achieving the same task

Different transport behaviours (strategies) that can be interchangeable
Strategy Pattern

Strategy Pattern
Currently, the code uses switch statements to handle each of the different cases.
How does the code violate the open/closed principle?
Strategy Pattern
Currently, the code uses switch statements to handle each of the different cases.
How does the code violate the open/closed principle?
- Not closed for modification / open for extension.
- Each new case requires a new
switchstatement.
How does this make the code brittle?
Strategy Pattern
Currently, the code uses switch statements to handle each of the different cases.
How does the code violate the open/closed principle?
- Not closed for modification / open for extension.
- Each new case requires a new
switchstatement.
How does this make the code brittle?
- Makes code more brittle as new requirements cause things to break/difficult to extend functionality
Let's refactor it!

Structure

Now that we have refactored, how about we want to add a new pricing strategy?
Notice how after refactoring, it is a lot easier to add additional functionality and we are no longer breaking the Open-Closed Principle.
Strategy Pattern
Find out more at Strategy (refactoring.guru)
Observer Pattern
Observer Pattern
What is it?
Behavioural pattern which defines a subscription mechanism that notifies observers about any event that happens to the subject that they are observing
What problem does it solve?
Modelling a n-to-many relationship may be difficult. If
not done well, it typically leads to tight coupling
When should we use this pattern?
When changing the state of one object requires changing other objects in turn
Observer Pattern
Subject
Maintains a list of observers and notifies them of state changes. During this notification, they are passing data (push/pull)
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers(data); // Calls update() of observersObserver
Register (and unregister) themselves on a subject and to update their state when they are notified.
// Two possible options for update()
public void update(Subject obj); // PULL data from subject
public void update(data); // PUSH data to observersObserver Pattern
Model the system in Java!


Structure
Mini Quiz
Which design pattern should we use for each of the following?
Represent tasks with subtasks, all supporting markComplete()
Mini Quiz
Which design pattern should we use for each of the following?
Represent tasks with subtasks, all supporting markComplete()
Composite Pattern
Mini Quiz
Which design pattern should we use for each of the following?
Represent tasks with subtasks, all supporting markComplete()
Composite Pattern
In a data analysis tool, switch between different sorting algorithms depending on the dataset needs
Mini Quiz
Which design pattern should we use for each of the following?
Represent tasks with subtasks, all supporting markComplete()
Composite Pattern
Strategy Pattern
In a data analysis tool, switch between different sorting algorithms depending on the dataset needs
Mini Quiz
Which design pattern should we use for each of the following?
News app (e.g., email alerts, mobile notifications) notifies when a new article is published
Represent tasks with subtasks, all supporting markComplete()
Composite Pattern
Strategy Pattern
In a data analysis tool, switch between different sorting algorithms depending on the dataset needs
Mini Quiz
Which design pattern should we use for each of the following?
In a data analysis tool, switch between different sorting algorithms depending on the dataset needs
News app (e.g., email alerts, mobile notifications) notifies when a new article is published
Represent tasks with subtasks, all supporting markComplete()
Composite Pattern
Strategy Pattern
Observer Pattern
COMP2511 Tute05
By Chirag Sawlani
COMP2511 Tute05
- 112