1.4.2 understand the use of immutable code
We have discussed immutability in the previous sections about the benefits of functional styles ). The example we use is an elliptic with a border, but the specific behavior of the Code is not clear. When we rewrite the Code with an immutable object, it becomes easier to understand. In the subsequent sections, we will return to this topic and discuss it in more detail. The purpose of this example is to display the performance of objects that are unchangeable in practice.
Once again, do not worry if you are not able to master it all at this time. Imagine that we are writing a game where the role is our goal and the role can be represented by a class. The following list is part of this class:
Listing 1.7 immutable representation of agame character (C #)
Classgamecharacter
{
Readonlyint health; | [1] declares all fields as read-only
Readonly point location; |
Public gamecharacter (INT health, pointlocation)
{
This. Health = health; | [2] initializing an unchangeable Field
This. Location = location; |
}
Publicgamecharacter hitbyshooting (point target)
{
Int newhealth = calculatehealth (target); | [3] returns a game role whose health value has been updated.
Returnnewgamecharacter (newhealth, this. Location); |
}
Publicbool isalive
{
Get {return Health> 0 ;}
}
// Other methods and properties omitted
}
In C #, we can clearly mark the field as immutable and use the readonly keyword. In this way, the field value cannot be changed. However, if this field points to a non-Immutable class [that is, referencing a variable class], the target object can still be modified. To create a truly unchangeable class, make sure that all fields are marked as readonly, and the field type is basic type, immutable value type, or other immutable class.
According to these conditions, the gamecharacter class is immutable. All its fields are marked with the readonly qualifier [1]. Int is an immutable basic type, and point is an immutable value type. When the field is read-only, the value can only be set when the object is created. Therefore, we can only set the role position and health value in the constructor [2]. In this way, after the object is initialized, its status cannot be modified. So what should we do when the operation needs to modify the game role status?
When you see the hitbyshooting method, you will know the answer [3], which achieves the game's reaction to shooting. It uses the calculatehealth method (not in this example) to calculate the new health value of the role. The role State needs to be modified in the imperative style, but this is not possible because the type is unchangeable. On the contrary, this method creates a new gamecharacter instance, which indicates the modified role and returns the result.
The class in the previous example is a typical design of an unchangeable C # class. We have always used this example in the book (with some modifications ). Now we know the immutable representation, and it is necessary to understand its impact.