Chapter 6 Protocol oriented programming.

Tram Ho

This book is about protocol oriented programming. When Apple announced swift 2 at WWDC 2015. They also defined Swift as the world’s first protocol-oriented language. From its name we also assume that protocol-oriented programming is all about protocol. However, this is a false assumption. Protocol-oriented programming has a lot more to it than that. It’s really a new way not only to write apps, but to think about programming as well.

In this chapter we will learn

  • What is protocol-oriented programming?
  • How do we use protocol aggregation?
  • How do we use the legacy protocol
  • How protocol-oriented programming compares to object-oriented programming.

In Chapter 5 object oriented programming, we saw how we design the vehicle type by object orientation. In this chapter, we will design the same vehicle type by navigating the protocol and comparing these two models.

After some advanced topics discussed in the previous chapter, the examples in this chapter look quite basic, like a step backwards. This is purely on purpose. The examples in this chapter are written to help you get started with protocol-oriented thinking and keep your thinking away from the object-oriented thinking. Once you do that you can start incorporating some of the advanced topics we’ve covered before.

This design pattern we cover in this chapter will cover the basics of protocol-oriented design and is written so that you start thinking in terms of protocol. You should not forget that some of the advantages we mentioned in previous chapters are like Generics.

Let’s start by reviewing the Vehicle requirements.

Requirements for sample code.

When we develop an application we often have a set of requirements we need to do. Our sample projects in this chapter and the chapters that follow are no different. Following a list of requirements for the vehicle type we are going to create:

  • We will have 3 categories of terrain for vehicles: waterway, road, and aviation. A vehicle can be a member of the three categories above
  • A vehicle can move or attack when it is in the square of any of the categories above.
  • Vehicles will not be able to move or attack on squares that do not match these types of terrain.
  • When a vehicle’s score returns to 0, it is considered inactive. We’ll keep the active vehicles in a single array and be able to traverse that array

For our blueprint in this chapter, we will demonstrate the design with only a few vehicles, but we know that the number of vehicles will increase as we develop the game. In this chapter we will not implement much logic for vehicles because we focus on design and not code to carry out attack and migration.

Now see how we design the facilities in a protocol-oriented approach

Swift is a protocol-oriented language. As We did with object-oriented design, we will start by creating a diagram that shows how to design media types in protocol-oriented styles. Like object oriented diagrams, this one is very basic, it simply shows their styles with no details.

The protocol-oriented design is a bit different from the object-oriented design. In object orientation we start with a parent class, which becomes the center of the blueprint and all child classes inherit properties and methods from the parent class.

In the protocol-oriented design we start designing with the protocol. Protocols and protocol extensions are at the heart of protocol-oriented design. However as we have seen throughout this book, protocol-oriented design is not just protocol.

In the new design we use three techniques to program the protocol-oriented different from the object-oriented. These techniques are protocol extensions, aggregation protocols, and protocol extensions.

Legacy Protocol is where a protocol can inherit requests from other protocols. This is similar to the derived class, but instead of inheriting the features from the superclass we will inherit the requests from the protocol. One of the advances in the inheritance protocol over the successor class in Swift is that the protocol can extend from many other protocols. In our example LandVehicle, SeaVehicle, AirVehicle inherits the requests from the Vehicle protocol. That’s an important note with a mix of protocol extensions and protocols. We have the ability to inherit features.

Associated Protocol allows for multiple types of satisfaction to more than one protocol. In our example there are several types such as Tank, Submarine, Jet that satisfy to a single protocol, however there are two types of Amphibious and Transformer get the benefit of the combinatorial protocol by satisfying multiple protocols.

Inheritance and association protocols are important in protocol-oriented design because they allow us to use them to create smaller and more specific protocols. This allows us to avoid bloating the superclass as we have seen in object oriented design. We need to be careful not to make the protocols too small because they will become difficult to maintain and manage.

Protocol extensions allow us to extend a protocol to provide complete methods and properties for types satisfying the protocol. This allows us the ability to provide them functionality to all types of protocol, eliminating the need to provide an implementation for each particular type or need to create a class hierarchy. While protocol extensions aren’t as interesting, you do need to understand how powerful they are, which will transform your way of thinking about application design.

Let’s start with creating the Vehicle Protocol. It will define a single attribute, hitPoints, to hold the vehicle’s remaining score

If you review the object oriented design, we have three methods defined in the superclass that all vehicle types will use. These methods are takeHit (amount :), hitPointsRemaining (), isAlive (). The implementations of these methods will be the same for each vehicle type, so they are the candidate to be executed in the protocol extensions section. The next code will show how we will create a Vehicle extension, and how we will execute these 3 methods in the extension.

Now, any type that conforms to the Vehicle protocol type or extends the protocol will automatically recognize these methods. Protocols that inherit requests from other protocols also inherit the features provided by protocol extensions

Now let’s see how we define the LandVehicle, SeaVehicle, AirVehicle protocols

There are a few things to note about the protocols. The first is that they all inherit the requirements from the Vehicle protocol. This means that they also inherit features in the Vehicle protocol extensions

Another thing to note about these protocols is that they contain only requirements required for their particular medium. Remember, the Vehicle superclass in object oriented design contains requirements for all types of vehicles. Dividing the requirements into 3 separate protocols makes the code more secure, easy to maintain, and easy to manage. If we need some general functionality we could add protocol extensions to each or all of the protocols.

We define properties for the 3 protocols with the get property, which means that we will define the properties as constants within the data type that satisfy the above protocols. This is obviously a big advantage when using protocol-oriented design because it prevents external code from changing the values ​​set for them, which can reduce errors and are difficult to investigate.

Now let’s see how we will create conformable types to the above protocols. We’ll create the same Tank, Amphibious, and Transformer styles we did in the object-oriented design. Let’s start with the Tank type

There are several differences with the Tank type defined here from the Tank type in the object oriented design. Let’s see these differences.

The first thing we can see is that the Tank type in object oriented design is the reference type, while in the protocol-oriented design it is the struct type of the reference type. The protocol-oriented design doesn’t tell us to use the type of argument, but it does say that we should prioritize this type. It also means that we can define the Tank type by class, this depends on the general design of the application.

One of the reasons for choosing a reference type over a reference type is because they are more secure. If you always get a copy of the value type then you can be confident that nowhere in our code can change our entity. This is especially useful in multi-thread environments where we don’t want other threads to be able to change the data while we are using that data. Because it can create bugs that are difficult to deal with. In our case, we will probably need the ability to allow a piece of code to modify the vehicle instance and or not. While this is not the default behavior of the parameter type, we can use inout before the parameter to achieve this goal. We’ll see how to do this in the next section of this chapter.

One difference between the two Tank types is that the one designed in a way the protocol can use the default constructor provided by the struct. and we can define properties as constants. Because some properties are constants, they cannot be changed once they have been set. In the Tank type of object oriented design, we have to override the constructor and then set the value inside that constructor. Attributes in object oriented design are defined as variables and they can be changed after they are set.

One thing we don’t see when we see two types of tanks is the Tank type in protocol-oriented design that only contains the functionality of land vehicles. The tank-style of the object-oriented design inherits the features and attributes of both the sea and the sky as well as on land, and it doesn’t even need those features.

Now see how we create Amphibious

The Amphibious type looks very similar to the Tank type, however it uses a composite protocol to satisfy many of the transport-type protocols. This allows it to have both land and sea features. Now let’s see how we can implement the Transformer style

Because the Transformer type can move and attack from 3 types of terrain, we use the composite protocol to satisfy the LandVehicle, SeaVehicle, and AirVehicle protocol.

Now see how we use these new styles. As in object oriented design we have the requirement to be able to keep these entities in a single array. This can allow us to traverse each active element of the array to perform the necessary actions. To do this we use polymorphism as we did in object oriented design, however for protocol-oriented design we will use the interfaces provided by the protocol to interact with entities of the media type. . Let’s see how we do this by creating an array and placing vehicle-type entities in it.

This code is exactly the same as in object oriented design. In the code we create an array that will store the entities that satisfy the Vehicle type. For the legacy protocol, this means that the array will be able to accept protocol types inherited from the Vehicle protocol. In our example this means that the array will accept the protocol entities LandVehicle, SeaVehicle, AirVehicle, and Vehicle.

The array, in this example, is defined to contain entities of type that satisfy protocol Vehicle. This means that we can use the interfaces defined by the Vehicle protocol to interact with the types in the array. Look at protocol Vehicle, which isn’t really helpful. However, we can try to cast the entity’s type so we can find if they satisfy a particular protocol. The following code snippet will demonstrate.

In this code, we use a for loop to traverse the array of vehicles. We use a cast to check if the entity satisfies a protocol like AirVehicle, LandVehicle, SeaVehicle. We will print out the location of that vehicle.

Accessing each element in an array this way is quite similar to how we did in object oriented design. What we want, however, is to get one data type rather than to get all the data types. We can do that with the where command. Follow the example below:

In this example we use the where keyword to filter the results for the for command to retrieve only the entities that satisfy the LandVehicle protocol. We can cast any entity returned from the for loop to agree to the LandVehicle protocol and interact with it using the interface provided by that protocol.

Now that we’ve finished our redesign, let’s summarize how protocol-oriented programming differs from object-oriented programming.

Summary of object oriented programming and protocol oriented programming.

In this chapter and chapter 5, the object-oriented programming we saw in Swift can be used for both types. In this chapter we have seen that there are 2 differences between 2 designs.

The first difference we see is that with the protocol-oriented design we should start with the protocol rather than with a superclass. We can use protocol extensions to add functionality to those that conform to the protocol or those that conform to the protocol inheriting from that protocol. With Object Oriented Programming we start with a superclass. When we design our vehicles in a protocol-oriented approach we convert the Vehicle superclass to the Vehicle protocol and then use the protocol extension to add the required functionality.

In the protocol-oriented example we use a legacy protocol and a federated protocol that allows us to create protocols with special requirements. This allows us to create exact types that contain only the features required for that type. In object oriented design, the exact types inherit all the features provided by the Vehicle superclass

The second big difference we’ve seen is the use of struct with parametric type rather than using class reference type for Vehicle type. The Apple documentation also states that party developers prefer to use greed over reference where appropriate. In our example, we used struct as a value, but we can use it as a value. We will discuss this later in this chapter.

Both the object-oriented design and the protocol-oriented design use polymorphism to allow us to interact with different types in a single interface. With object oriented design we use the interface provided by the parent class to interact with all child classes. In protocol-oriented design we use interfaces provided by the protocol and protocol extensions to interact with types that satisfy the protocol.

Now that we summarize the differences between object oriented design and protocol oriented design, let’s take a look at those differences in more detail,

Difference between object oriented programming and protocol oriented

I mentioned earlier in this chapter that protocol-oriented programming has more than just protocols. This is a new way not only to programming but also how to think about programming. In this section we will examine the differences between the 2 designs to see what is the meaning of this statement?

As a programmer, our ultimate goal is always to develop a workable application, but we also focus on writing clean and secure code. Clear code is easy to read and understand. It’s very important to write explicit code because whatever code we write will need to be maintained by someone else. And that person is usually the one who wrote it. There is nothing worse than looking at the code you have written and not being able to understand what it is. It’s also easy to spot errors in code if it’s clear and easy to understand.

Safe code means that code is difficult to break. It is not difficult for us programmers to make a small change in their code and then the error appears in the entire code. By writing code clearly, our code is inherently safe because other programmers will be able to understand the code and understand exactly what it does.

Now let’s compare the protocol and protocol extension with the superclass.

In object oriented programming we create the Vehicle parent class that will be inherited by all subclasses. In protocol oriented programming we use a combination of protocols and protocol extensions to achieve the same thing. There are, however, some advantages to the protocol-oriented type.

To refresh your memory for two solutions Let’s review the Vehicle and Protocol Vehicle superclasses and protocol extension.

The Vehicle superclass is a complete type we can instantiate from. This can be a good thing or a bad thing. There are a number of times like in the example when we shouldn’t create entities from superclass. This can still be done using the protocol for object oriented programming. However we need to use protocol extensions to add some general functionality and this brings us back to protocol oriented programming.

Now let’s see how we use protocols and protocol extensions in protocol-oriented design

We then create 3 protocols, each of which will be a vehicle type and use the legacy protocol to extend the requests and features from the Vehicle protocol. Those protocols are

The code in both of these solutions is very secure and easy to understand, however the protocol-oriented design is more secure. By separating the implementation from the definition and dividing the requirements into smaller and more detailed parts, we can eliminate the superclass bloat and also prevent types of inheriting features that it doesn’t. need.

There are 3 obvious advantages of protocols and protocol extensions in our design. The first advantage is that the types can conform to several types of protocols. This means that we can create multiple protocols that contain special features rather than create a single superclass. We can see in our example that the superclass Vehicle contains the features of land, sea, and sky while in the protocol-oriented design we can create 3 protocols each one corresponding to a vehicle type.

The second advantage of the protocol is that we use the protocol extension to add functionality without changing the original code. This means that we can extend any protocol even though the protocol is part of the swift language. To add functionality to our superclass we either need to have the code of that parent class or we need to create a subclass that inherits that superclass. Usually, however, we have to create a new data type that inherits the superclass. We can use the extension to add functionality to the superclass, but add functionality to a subclass structure. In Chapter 3 we saw why we should use it with caution when using extensions to add functionality to the hierarchy.

The third advantage of the protocol is that the protocol is accessible by class, struct, and enumeration. While the subclass structure is limited to the class type. The protocol gives us the choice to use the type of value in the right places.

Execute the Vehicle type.

The implementation of vehicle types is slightly different from object oriented and protocol oriented, however the difference is very significant. We’ll see the differences between the two examples, but first let’s look at the code again to remind us of how we implemented the Vehicle type. We will see how we implement the Tank type in an object oriented way.

This class is a subclass of the Vehicle parent class, and it implements a unique constructor. While this is a fairly simple and straightforward affair. We really need to fully understand what the parent class expects to execute the correct type. Example If we do not fully understand the Vehicle superclass we may forget to set the LandAttackRange value. In our example, forgetting to set the property value will result in the Tank type being invulnerable.

Now also see how we implement a protocol-oriented vehicle type.

The Tank type from the protocol-oriented design conforms to the LandVehicle protocol type and uses the default values ​​provided by the struct. We can say that the protocol-oriented design is much more secure and easy to understand because of the way the properties and constructors are implemented in both examples.

In object oriented programming, all properties are defined in the superclass as variables. We’ll need to review the code or documentation from the parent class to see what properties were defined and how they were defined. If we forget to set something up in the subclass, the compiler will still happily compile the application and not warn us.

For the protocol we also need to review the protocol or document the protocol to see the properties to implement them. The difference is here if we forget any request the compiler will error and refuse to compile until we set everything up properly. We can also define any property as a constant, whereas in object oriented design we have to define it as a variable.

Use the reference type and the reference type.

In this chapter we implemented means types as structs as parametric types. We also mentioned that it can implement these types by reference. The reason we say these entities represent a single vehicle in the game and whenever something happens to that entity as if it was attacked by other means we want to change that. saved.

When we pass an instance of the reference type to another piece of code we pass a copy of that entity rather than the original entity. This can lead to problems when we want to store the changes to use for our data type. Let’s see the problem in the following code. We start by creating a function that will update the damage to a vehicle type when it executes as a reference type as we do with object oriented design.

We can use this function like so:

It works as expected and at the end of the instance code vh of type Tank will have a remainder of 58. This will not work with the reference type. Even if the swift compiler still lets us execute, the vehicle instance in the takeHit method is a copy of the vh entity we passed, so any changes to the vehicle instance will not be saved back to the real instance. original form. There are many times when we want to do this, but there are times when we want the change to be saved. We can mimic this behavior of the reference type, but it takes a little more code. The following function will demonstrate how we can create a function that can accept an entity as a value and store any changes to its angular entity.

This function is defined as a generic function that accepts a variable that satisfies protocl Vehicle. This parameter is also marked as the input to the variable. This means that any changes made to the variable in the weld will be stored back to the original entity.

We’ll use the function like this:

when we call this function. we need to put the & in front of the entity of type Vehicle, which means we pass a reference of the entity, not the value. This also means that any changes made within the function will be saved to the original entity.

So which one is the better language. We all learn together.

The winner is….

But since we’ve read through this chapter and seen the advantages of protocol-oriented over object-oriented programming, we can think of protocol-oriented programming clearly over object-oriented programming. This assumption is not entirely correct.

Object-oriented programming has been around since 1970, it is a programming paradigm that has been tested in battle. Protocol-oriented programming is a new kid and they are designed to fix some of the problems of object-oriented programming. I have used protocol-oriented programming in a number of projects and I enjoy its capabilities very much.

Object-oriented and protocol-oriented programming have quite similar concepts for creating types of options for modeling objects in the real or virtual world. Both threads use polymorphism to use a single interface to interact with multiple data types. The difference is how we design the app.

In my personal opinion, the basics of a project using protocol-oriented programming is safer and easier to read when compared to object oriented programming. This does not mean that I will abandon object-oriented programming. I can see a lot of needs for the use of classifier and inheritance structures.

Remember, when we design our application we should use the right tools for the right thing. We wouldn’t want to use an unbroken machine to cut a small log, but we also don’t want to use a hand saw to cut a tree. So the winner is the programmer, where we choose to use different programming models rather than limit ourselves to just one.

Summary

In this chapter, we saw how we design facilities for a video game in a protocol-oriented approach. We have seen how we use the associative and legacy protocols, which allow us to create smaller and more specific protocols than a superclass. We also saw how protocol-oriented programming solves the problems we encounter when using object oriented programming.

In the next chapter we will see how to implement some of the popular designs using Swift. See you in the next chapter

Share the news now

Source : Viblo