Edit Page

Prototype

The prototype design pattern is one of the twenty-three well-known Gang of Four (GoF) design patterns. Recall that, design patterns are proven solutions to solve recurring design problems to design flexible and reusable object-oriented software; that is, objects that are easier to implement, change, test and reuse.

The prototype design pattern is often used to create objects by cloning an existing object called a prototype.

We may use the Prototype Pattern when it is considered expensive or complicated to create an instance of a given class by copying or cloning an existing instance.

Slides

Video

Code

Vehicle.java

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package vehicles;
import main.Person;

public abstract class Vehicle{

  private String make;
  private String model;
  private int year;
  private String color; 
  private int numWheels;
  private int mileage;
  private String plateNumber;
  private String vin;
  private Person owner;

  public Vehicle(String make, String model, int year, 
      String color, int numWheels, String vin, Person owner) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.color = color;
    this.numWheels = numWheels;
    this.mileage = 0;
    this.plateNumber = "";
    this.vin = vin;
    this.owner = owner;
  }

  @Override
  public abstract Vehicle clone();

  /* basic get and set accessors a.k.a getters/setters(mutators) */

  public String getMake() {
    return this.make;
  }

  public void setMake(String make){
    this.make = make;
  }

  public String getModel() {
    return this.model;
  }

  public void setModel(String model){
    this.model = model;
  }

  public int getYear() {
    return this.year;
  }

  public void setYear(int year){
    this.year = year;
  }

  public String getColor() {
    return this.color;
  }

  public void setColor(String color){
    this.color = color;
  }

  public int getNumberOfWheels() {
    return this.numWheels;
  }

  public void setNumberOfWheels(int numWheels){
    this.numWheels = numWheels;
  }

  public int getMileage() {
    return this.mileage;
  }

  public void setMileage(int newMileage) {
    if (newMileage < this.mileage) {
      throw new IllegalArgumentException();
    }
    this.mileage = newMileage;
  }
  public String getPlateNumber() {
    return this.plateNumber;
  }

  public void setPlateNumber(String plate) {
    this.plateNumber = plate;
  }

  public String getVin(){
    return this.vin;
  }

  public void setVin(String vin){
    this.vin = vin;
  }

  public Person getOwner(){
    return this.owner;
  }

  public void setOwner(Person owner){
    this.owner = owner;
  }

  @Override
  public String toString() {
    return "Make: " + this.make + "\nModel: " + this.model +
      "\nYear: " + this.year + "\nColor: " + this.color + "\nWheels: " +
      this.numWheels + "\nMileage: " + this.mileage + "\nPlate number: " 
      + this.plateNumber + "\nVIN: " + this.vin + "\nOwner: " + this.owner;
  }
}

Car.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package vehicles;

import main.Person;

public class Car extends Vehicle {
  private int seatingCapacity ;

  public Car(Car target) {
    super(target.getMake(), target.getModel(), 
        target.getYear(), target.getColor(), target.getNumberOfWheels(),
        target.getVin(), target.getOwner());
    this.seatingCapacity = target.getSeatingCapacity();
  }

  public Car(String make, String model, int year, 
      String color, String vin, Person owner, int seatingCapacity) {
    super(make, model, year, color, 4, vin, owner);
    this.seatingCapacity = seatingCapacity;
  }

  /* Clone this object by returning a new copy of the Car object. 
     This is a shallow clone (i.e. the vehicle's owner of type Person is shared
     with both the original object and the new cloned object.)
     */
  @Override
  public Vehicle clone(){
    return new Car(this);
  }

  // getters/setters(mutators)

  public int getSeatingCapacity(){
    return this.seatingCapacity;
  }

  public void setSeatingCapacity(int seatingCapacity){
    this.seatingCapacity = seatingCapacity;
  }

}

Minivan.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package vehicles;

import main.Person;

public class Minivan extends Vehicle {
  private int seatingCapacity;
  private boolean hasSlidingDoor;

  public Minivan(Minivan target) {
    super(target.getMake(), target.getModel(), 
        target.getYear(), target.getColor(), target.getNumberOfWheels(),
        target.getVin(), target.getOwner());
    this.hasSlidingDoor = target.getHasSlidingDoor();
  }

  public Minivan(String make, String model, int year, String color, String vin,
      Person owner, int seatingCapacity, boolean hasSlidingDoor) {
    super(make, model, year, color, 4, vin, owner);
    this.hasSlidingDoor = hasSlidingDoor;
    this.seatingCapacity = seatingCapacity;
  }

  /* Clone this object by returning a new copy of the Minivan object. 
     This is a shallow clone (i.e. the vehicle's owner of type Person is shared
     with both the original object and the new cloned object.)
     */
  @Override
  public Vehicle clone(){
    return new Minivan(this);
  }

  // getters/setters(mutators)

  public int getSeatingCapacity(){
    return this.seatingCapacity;
  }
  public void setSeatingCapacity(int seatingCapacity){
    this.seatingCapacity = seatingCapacity;
  }

  public boolean getHasSlidingDoor(){
    return this.hasSlidingDoor;
  }
  public void setHasSlidingDoor(boolean hasSlidingDoor){
    this.hasSlidingDoor = hasSlidingDoor;
  }

}

Motorcycle.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package vehicles;

import main.Person;

public class Motorcycle extends Vehicle {
  private String frameType;
  private boolean hasSidecar;

  public Motorcycle(Motorcycle target) {
    super(target.getMake(), target.getModel(), 
        target.getYear(), target.getColor(), target.getNumberOfWheels(),
        target.getVin(), target.getOwner());
    this.frameType = this.getFrameType();
    this.hasSidecar = target.getHasSidecar();
  }

  public Motorcycle(String make, String model, int year, 
      String color, String vin, Person owner, 
      String frameType, boolean hasSidecar) {
    super(make, model, year, color, 2, vin, owner);
    this.frameType = frameType;
    this.hasSidecar = hasSidecar;
  }

  /* Clone this object by returning a new copy of the Motorcycle object. 
     This is a shallow clone (i.e. the vehicle's owner of type Person is shared
     with both the original object and the new cloned object.)
     */
  @Override
  public Vehicle clone(){
    return new Motorcycle(this);
  }

  // getters/setters(mutators)

  public String getFrameType(){
    return this.frameType;
  }

  public void setFrameType(String frameType){
    this.frameType = frameType;
  }
  public boolean getHasSidecar(){
    return this.hasSidecar;
  }
  public void setHasSidecar(boolean hasSidecar){
    this.hasSidecar = hasSidecar;
  }

}
Truck.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package vehicles;

import main.Person;

public class Truck extends Vehicle {
  private int numberOfAxles;
  private float bedLength;

  public Truck(Truck target) {
    super(target.getMake(), target.getModel(), 
        target.getYear(), target.getColor(), target.getNumberOfWheels(),
        target.getVin(), target.getOwner());
    this.numberOfAxles = target.getNumberOfAxles();
    this.bedLength = target.getBedLength();
  }

  public Truck(String make, String model, int year, 
      String color, int numberOfWheels, String vin, Person owner, 
      int numberOfAxles, float bedLength) {
    super(make, model, year, color, numberOfWheels, vin, owner);
    // assuming the number of axles is the number of wheels divided by 2
    this.numberOfAxles = numberOfWheels / 2;
    this.bedLength = bedLength;
  }

  /* Clone this object by returning a new copy of the Truck object. 
     This is a shallow clone (i.e. the vehicle's owner of type Person is shared
     with both the original object and the new cloned object.)
     */
  @Override
  public Vehicle clone(){
    return new Truck(this);
  }

  // getters/setters(mutators)

  public float getBedLength(){
    return this.bedLength;
  }

  public void setBedLength(float bedLength ){
    this.bedLength = bedLength;
  }

  public int getNumberOfAxles(){
    return this.numberOfAxles;
  }

  public void setNumberOfAxles(int numberOfAxles){
    this.numberOfAxles = numberOfAxles;
  }

}
Person.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main;

public class Person {
  private String name;

  public Person(String name){
    this.name = name;
  }

  public String getName(){
    return this.name;
  }

  public void setName(String name){
    this.name = name;
  }

  public String toString(){
    return "Name: " + this.name;
  }
}
VehicleCache.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main;

import java.util.HashMap;
import java.util.Map;
import vehicles.Vehicle;
import vehicles.Car;
import vehicles.Minivan;
import vehicles.Motorcycle;
import vehicles.Truck;

public class VehicleCache {

  private Map<String, Vehicle> cache = new HashMap<>();

  public VehicleCache(){

    Car car = new Car("Honda", "Accord", 2020, "silver", "WBAKE3C52DE700756",
        new Person("Muhammad"), 5);
    Minivan van = new Minivan("Toyota", "Sieena", 2021, "white", "1N4CL2AP2BC107702",
        new Person("Bilal"), 8, true);
    Truck truck = new Truck("Ford", "F-150", 2021, "red", 4, "5TBRT34133S402382",
        new Person("Omar"), 2, 2.4f);
    Motorcycle bike = new Motorcycle("BMW", "R-1250", 2021, "black", "1M8PDMTA3TP010033",
        new Person("Ali"), "aluminum", false);

    // populate the cache
    cache.put("2020HondaAccord", car);
    cache.put("2021ToyotaSieena", van);
    cache.put("2020FordF150", truck);
    cache.put("2020BMWR1250", bike);
  }

  public Vehicle put(String key, Vehicle vehicle) {
    cache.put(key, vehicle);
    return vehicle;
  }

  // Return a cloned from the cache
  public Vehicle get(String key) {
    return cache.get(key).clone();
  }
}
App.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main;

import vehicles.Vehicle;

public class App {
  public static void main(String[]args){
    VehicleCache cache = new VehicleCache();
    Vehicle v1 = cache.get("2020FordF150");
    Vehicle v2 = cache.get("2020FordF150");
    Vehicle v3 = cache.get("2021ToyotaSieena");
    Vehicle v4 = cache.get("2021ToyotaSieena");

    // compare object's identities
    if (v1 != v2) {
      System.out.println("The 2020FordF150 objects are two different objects");
    }else {
      System.err.println("Error: the 2020FordF150 objects are exactly the same object");
    }
    // printing their content
    System.out.println("***************** Content *****************");
    System.out.println("v1:\n"+ v1);
    System.out.println("v2:\n"+ v2);
    System.out.println("*******************************************");

    if (v3 != v4) {
      System.out.println("The 2021ToyotaSieena objects are two different objects");
    }else {
      System.err.println("Error: the 2021ToyotaSieena objects are exactly the same object");
    }
    // printing their content
    System.out.println("***************** Content *****************");
    System.out.println("v3:\n"+ v3);
    System.out.println("v4:\n"+ v4);
    System.out.println("*******************************************");
  }
}

View the complete source code on GitLab