Home Articles

Prototype Design Pattern

Let us discuss how Prototype design pattern in this article:

Intent

It’s a creational pattern that is used when creating an object of a class is either expensive or complex.

Let’s say you have an object and you want to create copy of it. To create copy, you need know all requirements and there are chances some private properties are not available to you.

Prototype Design Pattern

What problem it solves?

How can objects be created so that which objects to create can be specified at run-time?

What are the benefits?

  1. Hides the complexities of making new instances from the client.
  2. Helps you create clone of class whose source code is not available to you.
  3. In some circumstances, copying an object can be more efficient than creating a new object.

When should you use this pattern?

  • Use the Prototype pattern when your code shouldn’t depend on the concrete classes of objects that you need to copy.
  • This pattern is useful when you are writing a component that needs to create new instances of objects without creating a dependency on the class initializer.
  • When you want to reduce the number of subclasses that only differ in the way they initialise their respective objects. Somebody could have created these subclasses to be able to create objects with a specific configuration.

When should you avoid this pattern?

Implementing clone() can be difficult when their internals include objects that don’t support copying or have circular references.

Pattern correct implementation check:

Change the initializer for the class or struct used for the prototype object and check whether a corresponding change is required in the component that creates clones.

Any related patterns:

This pattern is often used with factory, composition or decorator patterns.

Structure:

The Prototype pattern delegates the cloning process to the actual objects that are being cloned. The pattern declares a common interface for all objects that support cloning. This interface lets you clone an object without coupling your code to the class of that object.

Design Pattern Structure

An object that supports cloning is called a prototype. When your objects have dozens of fields and hundreds of possible configurations, cloning them might serve as an alternative to subclassing.

Swift automatically applies the prototype pattern when you assign a value type to a new variable. Values types are defined using structs, and all of the built-in Swift types are implemented as structs behind the scenes, meaning that you can clone strings, Booleans, collections, enumerations, tuples, and numeric types just by assigning them to a new variable. Swift will copy the value of the prototype and use it to create a clone. struct having reference types are shallow copied, they are deep copied only on modification.


    import Foundation

    protocol Cloneable {
        func copy() -> Any
    }

    class Message: Cloneable {
        var to: String
        var subject: String
        
        init(to: String, subject: String) {
            self.to = to
            self.subject = subject
        }
        
        func copy() -> Any {
            return Message(to: to, subject: subject)
        }
    }

    class DetailedMessage: Message {
        var from: String
        init(to: String, subject: String, from:String) {
            self.from = from
            super.init(to: to, subject: subject)
        }
        
        override func copy() -> Any {
            return DetailedMessage(to: to, subject: subject, from: from)
        }
    }

    class MessageLogger {
        var messages:[Message] = []
        
        func logMessage(_ msg: Message) {
            guard let messageCopy = msg.copy() as? Message else { return }
            messages.append(messageCopy)
        }
        
        func processMessages(_ callback: (Message) -> Void) {
            for msg in messages {
                callback(msg)
            }
        }
    }


    var logger = MessageLogger()
    var message = Message(to: "Joe", subject: "Hello")
    logger.logMessage(message)
    message.to = "Bob"

    message.subject = "Free for dinner?"
    logger.logMessage(message)
    logger.logMessage(DetailedMessage(to: "Alice", subject: "Hi!", from: "Joe"))
    logger.processMessages({msg -> Void in
        if let detailed = msg as? DetailedMessage {
            print("Detailed Message - To: \(detailed.to) From: \(detailed.from)" + " Subject: \(detailed.subject)")
        } else {
            print("Message - To: \(msg.to) Subject: \(msg.subject)")
        }
    })
    

In this example, I created aCloneable protocol, all prototypes need to conform to this protocol. There is another way to implement copy is by conforming to NSCopying protocol and for that class should conform to NSObject.

This is a free third party commenting service we are using for you, which needs you to sign in to post a comment, but the good bit is you can stay anonymous while commenting.