Common Practices: Data Structures vs Objects
Table of Contents
Introduction
There is a trivial but big difference between objects and data structures:
Objects hide their data and show their functions (methods)
Data structures show their data, but they have no functions
The difference seems trivial, but it has far-reaching consequences for maintainability.
Code built on top of data structures makes it easy to add new functions, but it makes it hard to customize data because existing functions have to be customized as well.
OOP makes it easy to add new classes without having side effects on existing functions. On the other hand, OOP makes it hard to add new functions to classes because whole class structures have to be adapted.
Mostly only the data changes, but not the functionality, and that's why we mostly use objects instead of type structs.
Don’t waste your time
If you have understood everything from the introduction and know what a double dispatch or the visitor pattern is, then it is not necessary to finish reading the chapter. In this case, proceed with https://ekvip.atlassian.net/wiki/x/bQAbYg
Explanation based on an example
Here is an example:
If a pneumatic cylinder is replaced by a servo axis because the axis is faster and still has more smoothness, the function remains the same, namely: move to home position and move to work position. It is effortless to develop a container-class for a servo axis with two teach positions that implements the interface
ICylinder
.
Sometimes it's more likely that the data stays the same but new functions are added. Here is a lame example:
For rectangular tabs of a battery cell, a vision system gives the positions of angles A B C and D. This data is stored in a structure. It is used to calculate the center point with the
CalculateCenter
function to weld the busbar on it. Now is there a new requirement that the machine should store the area of the tab for the product data. Here it is now very easy to add a new functionCalculateArea
.
There are now two consequences:
Developers should be careful with getters, setters, and properties of normal classes, because they can create dependencies between the client class and the inner data structure of an object.
For pure data transfer objects (DTOs) we use objects with a method to dispatch functionality and objects with the functionality, this technique is called double dispatch (two are objects necessary to dispatch it).
Double Dispatch
Double dispatch is a technique to extract methods to classes, it’s useful if to extend the functionality later. I will show how it works on data objects, to keep it simple I’ll use two shapes a rectangle and a square.
The rectangle has the two side lengths a and b as LREAL
The square has only one side length a as LREAL
The functionality will be calculate area and convert shape to json object.
Of course, we first define the interfaces IShape
, IShapeVisitor
, IRectangle
and ISquare
. Then we implement the classes Rectangle
, Square
, ShapeArea
and JsonShape
.
Interfaces
Implementation
Summary
The example shows well how objects can later be extended by functions. For example, it is not difficult to create a xml shape here. However, this flexibility comes at a price because if there is new data, such as the triangle shape, then the visitor interface IShapeVisitor
and therefore all visitors must be adapted.
We use data objects instead of data structures because these are more flexible, especially the access control, polymorphism for collections. Normally, it is not common that functionality changes because a cylinder is cylinder it can extend and retract. It is ok to use type structs inside the data object, sometimes it is necessary to use data structures inside data objects, e.g. if the TwinCAT xml server is used as a persistence service.