DEV Community

Stoian Dan
Stoian Dan

Posted on • Edited on

2

Swift's POP (Protocol Oriented Programming) paradigm in rea life

Introduction

Imagine we want to implement a sort of postal system, where messages can be sent from someone to the post office; where it will be accordingly dispatched to the right destination.

Beginning

We could go ahead and define a simple data model, that represents a message.
This entity holds the actual message (we'll call it content), and some meta-data, i.e. data about the message itself.

Since we want this message to be immutable and we don't want shared references of it, we can make it a struct, as opposed to a class:

struct Message {
   // the meta-data; who is sending this message
   let sender: String
   // also meta-data; the receiver of the message
   let to: String 
   // the actual content of the message
   let content: String
}
Enter fullscreen mode Exit fullscreen mode

The Dispatcher

Now that we have a data model, which will be a shared entity between sender (a person) and dispatcher (the postal office).
We can go ahead and imagine our dispatcher:

class Dispatcher {
    public func dispatch(_ message: Message) {
       print("Sending \(message.content) to \(message.to) from \(message.from)")
    }
}
Enter fullscreen mode Exit fullscreen mode

The Sender

Finally let's imagine the person sending the message:

class Person {
     private unowned let dispatcher: Dispatcher
     let name: String
     init(dispatcher: Dispatcher, ) {
        self.dispatcher = dispatcher
        self.name = name
     }

     public func sendMessage(of message: Message) {
         dispacher.dispatch(message)
   }
}
Enter fullscreen mode Exit fullscreen mode

Example

This looks ok. Let's see how it will look in practice:

    let dispatcher = Dispatcher()
    let helvidius = Person(dispatcher: dispatcher, name: "Helvidius")
    let jovinian = Person(dispatcher: dispatcher, name: "Jovinian")

   helvidius.sendMessage(of: Message(sender: helvidius.name, to: "Jovinian", content: "Hi Jovinian! How are you?"))
Enter fullscreen mode Exit fullscreen mode

The actual problem

Notice however, it's a bit odd that Bob has to specify he's the sender.
A person has a name, and if a person sends a message, he's always going to be the sender.
In fact, the current code could be exploited, supposing we'd offer anyone the ability to send messages (i.e. Person class would be a public API):

    let dispatcher = Dispatcher()
    let evilMike = Person(dispatcher: dispatcher, name: "Evil Mike")    
   evilMike.sendMessage(of: Message(sender: "Andy", to: "Sandy", content: "Hi Sandy! I'm Andy, and I think you look ugly!"))
Enter fullscreen mode Exit fullscreen mode

The solution!

Protocols could make our lives much more easy. To start, we've noticed every person has a name; it also s seems maybe not just persons can send messages. why not have machines be able to send messages as well? All we need after all, besides the content and receiver, is for the sender to identify himself.
We could use Swift's UUID type, and that would be a great idea! However, for the sake of simplicity, well stick to a name field, of type string:

protocol Sender {
   var name: String { get }
}
Enter fullscreen mode Exit fullscreen mode

Great! Now we could have a ton of other types that can be senders, like machines:

class Machine: Sender {
   let name: String
   let dispacher: Dispatcher

   init(name: String, dispathcer: Dispathcer) {
       self.name = name
       self.dispathcer = dispatcher
   }

   public sendHappyNewYear() {
       let date = Date.now

       let components = Calendar.current.dateComponents([.month, .day], from: date)

         if components.day == 1 && components.month == 1 {
                dispatcher.dispatch(Message(sender: "Robot1", to: "Sandy", content: "Happy new Year Sandy!"))
         }

   }
}
Enter fullscreen mode Exit fullscreen mode

However, the actual problem still remains, just about anyone can create a message and pretend to be someone else!
So here's where POP (Protocol Oriented Programming) comes more handy in place.

We can make the initializer (or constructor, if you will) of Message entity fileprivate!

struct Message {
   // the meta-data; who is sending this message
   let sender: String
   // also meta-data; the receiver of the message
   let to: String 
   // the actual content of the message
   let content: String

   fileprivate init(sender: String, to: String, content: String) {
      self.sender = sender
      self.to = to
      self.content = content
   }
}
Enter fullscreen mode Exit fullscreen mode

Great, now we can define an extension method on the Sender protocol. That is a method that anyone who's a sender, can automatically benefit from, even retroactively! I.e. entities that already conform to the Sender protocol before the extension method is introduced can benefit from!:

struct Message {
   ...
}

extension Sender {
   func createMessage(to receiver: String, content message: Message) -> Message {
    Message(sender: self.name, to: receiver, content: message)
}
}

Enter fullscreen mode Exit fullscreen mode

Now any sender can call the createMessage method, that will automatically use the name the Sender has, because remember, the only thing we know about a Sender is that he has a name, and we can make use of that name in protocol extensions.

Image of AssemblyAI tool

Challenge Submission: SpeechCraft - AI-Powered Speech Analysis for Better Communication

SpeechCraft is an advanced real-time speech analytics platform that transforms spoken words into actionable insights. Using cutting-edge AI technology from AssemblyAI, it provides instant transcription while analyzing multiple dimensions of speech performance.

Read full post

Top comments (0)

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay