Leveraging the prototype pattern

If you're using value types, you will not find yourself needing to implement the prototype pattern, as value types implement copy-on-write.

Let's use our Article object from the previous example again, but this time as a class, so we don't benefit from the copy-on-write given by the value types:

class Article {
private(set) var id: String
let title: String
let message: String
let author: String
let date: Date
var views: Int

init(id: String,
title: String,
message: String,
author: String,
date: Date,
views: Int) {
self.id = id
self.title = title
self.message = message
self.author = author
self.date = date
self.views = views
}
}

Now we have Article following reference-type semantics, and we needed to add a constructor. Once again, Sourcery can be very helpful for generating this code instead of writing it by hand.

Let's have a look at the copy feature for this object:

extension Article: NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
return Article(id: id,
title: title,
message: message,
author: author,
date: date,
views: views)
}
}

Our article doesn't have any mutable fields other than the views count. So, if we want this article to be editable, we should probably implement a mutable copy of it:

extension Article: NSMutableCopying {
func mutableCopy(with zone: NSZone? = nil) -> Any {
return MutableArticle(id: id,
title: title,
message: message,
author: author,
date: date,
views: views)
}
}

The MutableArticle class is pretty much the Article class with all members marked as mutable usingĀ var.

Now, when needing to edit an article, it is possible to use mutableCopy() to acquire a copy on which the properties can be edited. MutableArticle should also implement NSCopying so it is possible to return a copy of the object that will be theĀ Article itself:

func editContents(article: Article, contents: String) -> Article {
let mutableArticle: MutableArticle = article.mutableCopy()
mutableArticle.contents = contents
return mutableArticle.copy()
}

As we have seen, the amount of boilerplate can be high when implementing this pattern as well. Let's have a look how Sourcery can help.