Have you worked with Outlook calendar or any other mature calendar, that allows you copy some events from day to day?
For example your friend scheduled small beer party for Friday, 23 July where he listed his friends, also he allocated time from 7pm till 3 am and put high priority, he also described that it is great to have party on Friday after work in the comments. As you were invited, party went extremely well. In the end of party your friend decided to schedule similar party for the next Friday, but since he had already drunk too much it was complicated for him to populate all of the fields of the event in calendar. Which kind of enhancement would you propose for the calendar, your friend uses? Probably copy-paste functionality.

PROTOTYPE

Prototype is design pattern, that allows us create complete copies of instances already defined in design (list of possible types of events) or either run-time(Friday’s event), so we no longer need reinstantiate them from A to Z. Already defined instances are called prototypical instances.

As we already described one applicability of Prototype for copying instances specified at run-time, this design pattern could be also used for reducing number of subclasses in the system. For example instead of having subclasses like “5 floors apartment block with 3 rooms flats“, “9 floors apartment block with 2-3-4 rooms flats” and “12 floors apartment block with 1-2-3 rooms flats” you may have 3 instances of ApartmentBlock initialized with needed properties, and then you just copy one of them when you need to build new building somewhere in the city. In other words no need to write either this “new ApBlockWith9FloorsAnd234Flats()” or this “new ApartmentBlock(){Floors = 9; FlatsDic = {2,3,4}}“.

What you need is something like “_9FloorsApBlock.Clone()“. Of course you can combine this with FactoryMethod, so you will have something like “GetMe9FloorsAppBlock()“, which inside calls cloning of prototypical instance.

Example

Let’s now take a look at Prototype, which defines clone() method for our prototypes.

public class CalendarPrototype implements Cloneable{
    @Override
    public CalendarPrototype clone() throws CloneNotSupportedException{
        CalendarPrototype copyOfPrototype = (CalendarPrototype)super.clone();
        return copyOfPrototype;
    }  
}

My concrete Prototype class is calendar event, which looks like this:

public class CalendarEvent extends CalendarPrototype {

    ArrayList<Attendee> _attendees = new ArrayList<Attendee>();
    Priority _priority; // priority is reference variable  
    Date _startDateAndTime = new Date();
   
    //setters and getters here
}


Client code
is executed, when my friend wants to open calendar, right click on event and paste it into other location, therefor changing start/end date & time.

Take a look on this process:

public class PrototypeDemo {

    public CalendarEvent getExistingEvent(){
        CalendarEvent beerParty = new CalendarEvent();
        ArrayList<Attendee> friends = new ArrayList<Attendee>();
        Attendee andriy = new Attendee();
        andriy.FirstName = “Andriy”;
        andriy.LastName = “Buday”;
        friends.add(andriy);
        beerParty.set_attendees(friends);
        beerParty.set_startDateAndTime(new Date(2010,7,23,19,0,0));
        beerParty.set_priority(Priority.High());

        return beerParty;
    }

    public void Run() throws CloneNotSupportedException {

        CalendarEvent beerParty = getExistingEvent();

        CalendarEvent nextFridayEvent = (CalendarEvent) beerParty.clone();

        nextFridayEvent.set_startDateAndTime(new Date(2010,7,30,19,0,0));


        // we will talk about further code a bit later

        nextFridayEvent.get_attendees().get(0).EmailAddress = “andriybuday@liamg.com”;
        nextFridayEvent.get_priority().setPriorityValue(0);      
       
        if(beerParty.get_attendees() != nextFridayEvent.get_attendees())
        {
            System.out.println(“GOOD: Each event has own list of attendees.”);
        }
        if(beerParty.get_attendees().get(0).EmailAddress == nextFridayEvent.get_attendees().get(0).EmailAddress)
        {
            //In this case it is good to have shallow copy of the attendees.
            System.out.println(“GOOD: If I updated my e-mail address it will be updated in all events.”);
        }
        if(beerParty.get_priority().isHigh() != nextFridayEvent.get_priority().isHigh())
        {
            System.out.println(“GOOD: Each event should have own priority object, fully-copied.”);
        }
    }
}

As you can see my friend got copy of the existing event and by grag-drop changed its date. But after that I noticed that I can change my address in his attendees list, so I did that, also after we got another beer and felt sick we decided to lower priority to neutral with this line: nextFridayEvent.get_priority().setPriorityValue(0);

Looks like we’ve got what we want – copy of the existing event, with attendees, priority, etc. But it turns out that when I open old event I see that priority is now neutral, not high. As you already guessed that is because we executed shallow copy.

Shallow copy copies only direct value field and keeps same references.
Deep copy copies whole graph of objects, so they all have different addresses in heap.

CLONE

For Prototype we can implement clone() our own way, so for example I can have partially deep copy, so my new address should be the same in all events, but priority should keep different.

In Prototype design pattern we implement clone method. Sometimes we may need complete deep copy which can be archived by manual copying which is cumbersome, by reflection, which could be slow, or by serializing and deserializing to new object, which is also expensive. But sometimes you need partial deep copying like in our example. That is why programming languages introduces Cloneable interfaces to be implemented by our own. Suitalbe for our example could look like:

    @Override
    public CalendarPrototype clone() throws CloneNotSupportedException {
        CalendarEvent copy = (CalendarEvent)super.clone();
       
        // this allows us have another list, but same attendees there
        ArrayList<Attendee> copiedAttendees = (ArrayList<Attendee>) this.get_attendees().clone();
        copy.set_attendees(copiedAttendees);

        // we also would like to copy priority
        copy.set_priority(this.get_priority().clone());

        return copy;
    }

   
I already wrote console outputs that say we are ok. But also here is screenshot from debug mode to prove that I do not cheat:

Hope this article wasn’t boring and brought more understanding of Prototype design pattern. Please let me know what you think about it!


Here is my Design Patterns Table.

If you haven't subsribed yet, you can subsribe below: