Say I'm using Parse Server and utilising the PFObject class from the iOS SDK. Say I want to have a Chat class.
To use inheritance code (design 1):
import Foundation
import Parse
class ChatInheritance: PFObject, PFSubclassing {
init(parseObject: PFObject, chatStatus: ParseChatStatus? = nil) {
self.parseObject = parseObject
self.chatStatus = chatStatus
}
var chatStatus: ChatStatus? {
set {
self["status"] = newValue
}
get {
return self["status"]
}
}
var lastMessage: ParseMessage? {
get {
return parseObject.objectForKey("lastMessage")
}
set {
parseObject.setObject(newValue, forKey: "lastMessage")
}
}
var participants: [User]? {
get {
return self["participants"]
}
set {
self["participants"] = newValue
}
}
func participantsWithoutUser(user: User) -> [User] {
return participants.filter { $0 != user }
}
class func parseClassName() -> String {
return "Chat"
}
}
About 55 lines of code.
The composition route being proposed is involves this construction (design 2)
import Foundation
protocol Chat {
var chatId: String { get }
var participants: [User] { get }
var lastMessage: ChatMessage { get set }
var chatStatus: ChatStatus? { get }
var updatedAt: NSDate { get }
func participantsWithoutUser(user: User) -> [User]
}
and then utilising delegation essentially to create the ParseChat class:
import Foundation
import Parse
class ParseChat: Chat {
var parseObject: PFObject
private var parseParticipants: [User]?
private var parseLastMessage: ParseChatMessage?
init(parseObject: PFObject, chatStatus: ParseChatStatus? = nil) {
self.parseObject = parseObject
self.chatStatus = chatStatus
}
var chatId: String {
return parseObject.objectId!
}
private(set) var chatStatus: ChatStatus?
var lastMessage: ChatMessage {
get {
if let parseLastMessage = parseLastMessage {
return parseLastMessage
} else {
parseLastMessage = ParseChatMessage(parseObject: parseObject.objectForKey("lastMessage") as! PFObject)
return parseLastMessage!
}
}
set {
parseLastMessage = (newValue as! ParseChatMessage)
parseObject.setObject(parseLastMessage!.parseObject, forKey: "lastMessage")
}
}
var participants: [User] {
if let parseParticipants = parseParticipants {
return parseParticipants
} else {
let parseUsers = parseObject.objectForKey("participants") as! [PFUser]
var users = [User]()
for u in parseUsers {
users.append(ParseUser(parseObject: u) as User)
}
parseParticipants = users
return users
}
}
var updatedAt: NSDate {
return parseObject.updatedAt!
}
func participantsWithoutUser(user: User) -> [User] {
return participants.filter { $0 != user }
}
}
Approximately 90 lines of code. Also, by inheriting from PFObject I get a lot of functionality for free.
One of my most valued design principles is "less code is better", and clearly since there is significant heavy lifting and functionality in the PFObject class I want to utilise, why would I every choose the Protocol + Delegate method (design 2), at least in this case?