CPSC 210

D8 Cont'd & Design Review

(last lecture 😢👋)

Lecture Lab

More (fun with) Iterators

More (fun with) Iterators

OneThenTwo

Alternating

Cartesian

More (fun with) Iterators

OneThenTwo

Alternating

Cartesian

More (fun with) Iterators

OneThenTwo

Alternating

Cartesian

More (fun with) Iterators

Strategy

Reminder

Teaching

Evaluations

Please

Reminder

Teaching

Evaluations

Please

Design Review

From high-level design principles to a sample of concrete design patterns

  • Well-designed software has high cohesion and low coupling
     
  • Most design patterns improve on cohesion and coupling

Cohesion

Every class should have a
single responsibility

Coupling

Measure how system components depend on each other

Liskov Substitution Principle

  • Design principle that states:
    • when a subtype is substituted for its super type:
      • the subtype must provide the expected behaviours of the super type

Refactoring

  • We refactor our code to improve on:
    • the design of our codebase
    • coupling by abstracting duplicated code
    • cohesion by splitting up classes

Design Patterns

We make mistakes

We identify our mistakes

We learn from our mistakes

We prevent mistakes

We Evolve Design Patterns

Lessons Learned!

Composite

I have a tree structure and I don't know all the types of objects in the tree

Run operations recursively through my tree without knowing the types in my tree

Observer

I want objects to know about a state but I don't know what these objects are

Objects can be added and removed as they desire

Singleton

I want to coordinate a state across my system

There is always exactly one instance of this state in my system

Iterator

I have a collection of elements and there should always be a "next" element

Traverse elements without exposing its implementation

ArrayListIterator<E>
LinkedListIterator<E>
HashSetIterator<E>

Iterable<E>

Iterator<E> iterator()

<<interface>>

Iterator<E>

boolean hasNext()
E next()
void remove()

<<interface>>

Collection

<<interface>>

Design patterns help us with the design of our code base

  • But language design also improves over time
  • Some examples...
Iterator<Item> itr = collection.iterator();
while (itr.hasNext()) {
  Item nextItem = itr.next();
  // do something with nextItem
}

Before Java 5

Since Java 5 (2004)

for (Item next : collection) {
    // do something with next
}
button.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
    System.out.println("Do something");
  }
});

Before Java 8

button.addActionListener(e -> {
  System.out.println("Do something");
});

Since Java 8 (2014)

List<String> list = new ArrayList<>();
list.add("dog");
list.add("cat");
list.add("hamster");

Before Java 9

List<String> list = List.of(
  "dog", "cat", "hamster");

Since Java 9 (2017)

Map<String, Integer> map = new HashMap<>();
map.put("dog", 1);
map.put("cat", 5);
map.put("hamster", 7);

Before Java 9

Map<String, Integer> map = Map.of(
  "dog", 1, "Cat", 5, "Hamster", 7);

Since Java 9 (2017)

Libraries and Frameworks also help us with design

  • Sometimes it's a good idea to look what's out there to help us write good code!
     
  • One example... you may want to update your projects... 😉

Lombok

public class User {
  private String firstName;
  private String lastName;
  private int age;
  private String email;

  public User(String firstName, String lastName, 
              int age, String email) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.email = email;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public String getFirstName() {
    return firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public int getAge() {
    return age;
  }
  public String getEmail() {
    return email;
  }
}
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {
  private String firstName;
  private String lastName;
  private int age;
  private String email;
}

Where to next?

  • Now that you have taken CPSC 210, you should be more than capable to build fairly sophisticated software in most other modern programming languages!
     
  • Let's look at the same code in a couple of different languages just to see...
     
  • Note: this is just for fun and the comparison is definitely not examinable!

Syntax is the easy part!

public class Test {
    public static void main(String args[]) {
        String array[] = {"Hello, World", "Hi there, Everyone", "6"};
        for (String i : array) {
          System.out.println(i);
        }
    }
}

Java

stuff = ["Hello, World!", "Hi there, Everyone!", 6]
for i in stuff:
    print(i)

Python

fn main() {
    let stuff = vec!["Hello, World!", "Hi there, Everyone!", 6];
    for i in stuff.iter() {
        println!("{}", i);
    }
}

Rust

Error messages

public class NullPointerExample {
    public static void main(String[] args) {
        String someVariable = null;
        someVariable.length();
    }
}

Java

# Attempting to call a method on a None object
some_variable = None
some_variable()

Python

fn main() {
    let some_variable: Option<&str> = None;
    some_variable.unwrap();
}

Rust

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "someVariable" is null
        at NullPointerExample.main(NullPointerExample.java:4)
TypeError: 'NoneType' object is not callable
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:3:5

Inheritance in Java and Python

... and more!

Hope you had a good time!
We certainly did!

 

Good luck on the Final Exam!

This was CPSC 210!