Monday, July 6, 2015

OOP – how to do it right? – attributes

primitive types and objects

The values of attributes of particular objects are the things that allow us to recognize a specific object to determine whether two objects are different or similar. It lets us identify instances of the class.

We can categorize attributes into two types:
  • Primitive types: byte, short, int, long, float, double, boolean and char.
  • Objects – they’re implemented as an aggregation - association or composition.

Attributes which types are primitives are the one which are directly related to the instance of an object. On the other hand, aggregations define an object’s relations.

We distinguish the following types of aggregations:
  • Association – the object which is a part can exist on its own, even when it’s not a part of relation.
  • Composition – the object which is a part that cannot exist without main object. It cannot be shared with any other object. If the main object is removed, then all its compositions as well.

To give you an example, I will use domain that is well known to all of us – software development.

Let’s assume that our application (specific instance) has its name (attribute) – let’s call it Training System. As it goes with any other software, tons of lines of code must have been written. Tons lines of code were used to make it work. We have used libraries, frameworks and ORMs. We have also code of domain and all the code that was written for this specific application.
All of those libraries, frameworks and ORMs are associations. They aren’t dependent on life cycles of our software and they "live their own lives” . They can be reused in other projects.
On the other hand, the code that was written to make our software work is a composition. It makes no sense without context and when our software becomes unneeded, the code will be thrown out with it.

I’m leaving an open question for you about domain? What types of aggregation is it? I’m waiting for your answers in comments :)

attribute’s access modifiers

In my opinion, each attribute should by default be private. And only if there’s a really good reason (but really, really good one) we can consider whether we should make it more visible or not. It’s important to remember that one of the main paradigm of OOP is encapsulation. And it clearly stands for NOT sharing with the others your implementation details.

Public attributes? Well, except an object, whose purpose is to transfer information (Data Transfer Object) I believe that I have never seen a situation when there were good arguments for making object’s attributes public. The most often reason is laziness. It’s just easier to directly get something from the object than to think how to solve it in a nice and proper way.

We can also make our attributes protected. You should use it rather rarely, though. Unless you do not plan to extend your class, then you should consider only private and public attributes. If you think that “maybe in future, but I don’t know yet when and if it even happens”, then do not use the protected one. If there is a need in the future, you always will have a chance to change your code.

On the other hand, if you make them protected just from the beginning, then the developer who will have to work with this code can be little bit confused, because she will look at your code, take another look and she will start thinking what was the reason of doing it. Because there needs to be a reason. There always is. Well, unfortunately it was not the case here.

We can always leave access modifier in its default state which makes it behave like public in a package scope and like private outside the package. This is sometimes really useful, because it allows us to look at a package as a whole and at classes inside like parts of something bigger.
Sometimes part of the code is just getting bigger and you want to extract a piece of code to make it more readable and maintainable, but you don’t want to share it anywhere else. In that case it is worth considering default access modifier.

To sum up, you should make all attributes private by default (not leave them in their default state :).
If there is a really good reason, but really good one, then make them public. But before doing this, think once again and try to challenge your idea. After this think a few more times, because usually it is a sign that “something went wrong”. And finally, if it really will make sense then make it public.
You should do the same if you would like to leave access modifier in its default state. You should ask yourself and challenge this solution. Only then let yourself do so.
You should not consider usage of protected visibility if you don’t plan to extend this class. If this condition is fulfilled, then ask yourself: "will the subclass really need to know about this attribute or not?” If the answer is yes, then ok, make your attribute protected.

And last thing at the end. You need to remember that if you are changing visibility from private to anything else, you are losing full control on the value this attribute can take. It can be changed from outside or by subclasses.

and how it looks like in code?

Let’s assume that we have to create software for a transporting company. One of the part will be contactors repository. To add a contractor, the user will need to specify his name and EIN (Employer Identification Number). There has to be possibility to create an invoice and send an email with it to the company’s customers.
From the other side, company need a possibility to make a money transfer to a bank account of contractor who delivers services for them.
This is an international company so there has to be a possibility to use bank accounts with different currencies. Some of the contractors have many people who need to receive invoices.
Additionally, it must be possible to specify contractor’s address.

Ok… enough :) let’s try to write some code.

First thing that we know is that Contractor must have EIN and a name:
class Contractor {
       private EmployerIdentifcationNumber ein
       private Name name;
}

The contractor can have many bank accounts which are determined by its currency. Because the number of the bank account and its currency are closely related, we will create one class which will present bank account:
class BankAccount {
       private AccountNumber number;
       private Currency currency;
}
 
class Contractor {
       private EmployerIdentifcationNumber ein
       private Name name;
       private List<BankAccount&t; bankAccounts;
}

Because invoices can be sent via company email address, we need something more. But if we would read requirements carefully we can see there can be more than one contact person. So it would be a good idea to assign such an address to a specific person:
class ContactPerson {
       private Name name;
       private Email email;
}
 
class Contractor {
       private EmployerIdentifcationNumber ein
       private Name name;
       private List<BankAccount&t; bankAccounts;
       private List<ContactPerson> contactPersons;
}

There needs to be also possibility to specify Contractor’s address. Because address is determined by lots of information (street, house number, zip code, etc.) we will put all this information into one place:
class Address {
       private StreetName street;
       private NonNegative houseNumber;
       private ZipCode zipCode;
       private City city;
}
 
class Contractor {
       private EmployerIdentifcationNumber ein
       private Name name;
       private List<BankAccount> bankAccounts;
       private List<ContactPerson> contactPersons;
       private Address address;
}

When we finally have a basic structure, we can start to think about objects’ behavior and application functionality.

But we will do it in next articles.

I’m waiting for your suggestions and comments. See you next time.




In this series I also wrote about:

No comments:

Post a Comment