Recognizing actions to create methods
So far, we have designed six classes and identified the necessary properties for each of them. Now, it is time to add the necessary pieces of code that work with the previously defined properties to perform all the tasks. We have to make sure that each class has the necessary encapsulated functions that process the property values specified in the objects to perform all the tasks.
Let's forget a bit about the similarities between the different classes. We will work with them individually as if we didn't have the necessary knowledge of geometric formulae. We will start with the Square
class. We need pieces of code that allow each instance of this class to use the value of the lengthOfSide
property to calculate the area and perimeter.
Tip
The functions defined in a class to encapsulate the behavior of each instance of the class are known as methods. Each instance can access the set of methods exposed by the class. The code specified in a method can work with the properties specified in the class. When we execute a method, it will use the properties of the specific instance. Whenever we define methods, we must make sure that we define them in a logical place, that is, in the place where the required data is kept.
When a method doesn't require parameters, we can say that it is a parameterless method. In this case, all the methods we will initially define for the classes will be parameterless methods that just work with the values of the previously defined properties and use the formulae shown in the figures. Thus, we will be able to call them without arguments. We will start creating methods, but we will be able to explore additional options based on specific Swift features later.
The Square
class defines the following two parameterless methods. We will declare the code for both methods within the definition of the Square
class so that they can access the lengthofSide
property value:
calculatedArea
: This method returns a floating point value with the calculated area for the square. It returns the square of thelengthOfSide
attribute value (lengthOfSide2 or lengthOfSide ^ 2).calculatedPerimeter
: This method returns a floating point value with the calculated perimeter for the square. It returns thelengthOfSide
attribute value multiplied by 4 (4 * lengthOfSide).
Note the usage of Camel case, that is, using a lowercase first letter, for method names. The first letter is in lowercase, and then, the first letter for each word that composes the name is capitalized, while the other letters are in lowercase. As it happened with property names, it is a coding convention in Swift for methods.
These methods do not have side effects, that is, they do not make changes to the related instance. The methods just return the calculated values. Their operation is naturally described by the calculate
verb. We use calculated
instead of calculate
as the first word for their names because the verb's imperative must be used for mutating methods. In this case, the methods are nonmutating, and we follow the API design guidelines that Apple provided for Swift 3.
Swift uses a dot (.
) to allow us to execute the methods of the instances. Imagine that we have two instances of the Square
class: square1
with the lengthOfSide
property equal to 20
and square2
with the lengthOfSide
property equal to 40
. If we call square1.calculatedArea
, it will return the result of 202, which is 400. If we call square2.calculatedArea
, it will return the result of 402, which is 1600. Each instance has a diverse value for the lengthOfSide
attribute, and therefore, the results of executing the calcualteArea
method are different.
If we call square1.calculatedPerimeter
, it will return the result of 4 * 20, which is 80. On the other hand, if we call square2.calculatePerimeter
, it will return the result of 4 * 40, which is 160.
Now, let's move to the EquilateralTriangle
class. We need exactly two methods with the same names specified for the Square
class: calculatedArea
and calculatedPerimeter
. In addition, the methods return the same type and don't need parameters, so we can declare both of them as parameterless methods, as we did in the Square
class. However, these methods have to calculate the results in a different way, that is, they have to use the appropriate formulae for an equilateral triangle. The other classes also need the same two methods. However, each of them will use the appropriate formulae for the related shape.
We have a specific problem with the calculatedPerimeter
method that the Ellipse
class generates. Perimeters are complex to calculate for ellipses, so there are many formulae that provide approximations. An exact formula requires an infinite series of calculations. We can use an initial formula that isn't very accurate, which we will have to improve later. The initial formula will allow us to return a floating point value with the calculated approximation of the perimeter for the ellipse.
The following figure shows an updated version of the UML diagram with the six classes, their attributes, and their methods: