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

  • TrainingSystem is needlessly tightly coupled with Trainer and Seminar
  • TrainingSystem has low cohesion as it relies on classes that are not its closest friends to achieve its purpose
  • Seminar has no control over the number of attendees. It relies on TrainingSystem to restrict number of attendees. This makes Seminar hard 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. TrainingSystem no longer has any knowledge of Seminar
  • 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 Seminar class 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 switch statement.

 

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 switch statement.

 

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

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 observers

Observer

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 observers

Observer Pattern

Model the system in Java!

Structure

Observer Pattern

 

Find out more at Observer (refactoring.guru)

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

Made with Slides.com