ENCAPSULATION
Consider an address: let's say it has a number and street name only
Java code for this could be :
- String number = "52";
- String street = "The Leeway";
- System.out.println(number +" " + street);
Ok so we see all the variables and the means to which the street was printed to us, if we encapsulate though we can do this:
- public class Address {
- private String streetName;
- private String number;
- public Address(String streetNametName, String number){
- this.streetName = streetNametName;
- this.number = number;
- }
- public String getStreetName() {
- return streetName;
- }
- public void setStreetName(String streetName) {
- this.streetName = streetName;
- }
- public String getNumber() {
- return number;
- }
- public void setNumber(String number) {
- this.number = number;
- }
- public String fullDescription() {
- return this.number + " " + this.streetName;
- }
- }
Ok, so this class has all the details of what data we are holding and defines how we can get and set that data vis accessors (getX allows us to get the value of x and setX allows to set a value to x).
- public static void main(String[] args) {
- Address address = new Address("The Leeway", "67");
- System.out.println(address.fullDescription());
- }
Above notice how we have to use the accessors to get our data and we use the constructor to pass our data in, we can choose to set new values later if we want using the setters.
The benefits:
by encapsulating our address we now have an app-wide mechanism for handling addresses, we can be sure that when we call fullDescription the result will be consistent across the entire app if a user uses fullDescription method.
We also define how we get and set our values, we cannot directly manipulate the variables this is useful because it means we have control on how are variables are manipulated; I could apply a builder pattern to this and ensure the values for addresses are immutable for instance.
I am not so far into Haskell so it surprises me to find it has sub-typing being a functional language so it could be a functional construct I am not aware of so this may very well be wrong in the context of Haskel but this is sub-tying in terms of java for sure.
So Encapsulation lets us group data and functionality together and hides the implementation from the developer which is good but sometimes we want to have functionality that is common to many classes.
Consider Animal, an animal has a genus, it has a habitat and it is either a carnivore, herbivore, or omnivore.
A dog is an animal but it is also a dog, it shares all the characteristics of an animal and has characteristics that only a dog has such as say a method called chasePostman so let's see how we do that via subtyping:
- public abstract class Animal {
- private String genus;
- private String type; //Carnivore, omnivore or herbivore normally we would use a enum public String getGenus() {
- return genus;
- }
- public void setGenus(String genus) {
- this.genus = genus;
- }
- public String getType() {
- return type;
- }
- public void setType(String type) {
- this.type = type;
- }
- }
So above is the animal class, notice how it is abstract so we can not instantiate it as an animal, this is known as the super type for whatever sub-types it.
- public class Dog extends Animal{
- public void chasePostman(){
- System.out.println("Ruff ruff");
- }
- }
Above is the dog class, it is a sub-type of the super-type Animal.
- public static void main(String[] args) {
- Dog milo = new Dog();
- milo.setGenus("");
- }
As Dog is a subtype of Animal I have access to all the public and protected methods and variables in Animal.
Sub-typing is useful as when using this and encapsulation you can create logical, reusable classes that provide simple ways of storing to memory and using data in your application, I could create the class Cat and Lizard with each being a subtype of Animal, Animal can therefore hold all actions and variables associated with being an Animal meaning that I have a lot of reusable code and have prevented duplication of code through my application.
Additionally, we now are taking advantage of polymorphism, milo is a Dog but is also an Animal, lets say we had a method that worked out if two animals were the same genus (example method only bare with me)
- public static boolean isSameGenus(Animal a, Animal b) {
- return Objects.equals(a.getGenus(), b.getGenus());
- }
We want this method to be able to check every animal but we don’t care if it is a Dog or a Cat, we let each argument be a Animal, as milo is indeed a Animal we can pass milo into this hypothetical method along with say Seth the snake to see if they are the same genus or not.
Likewise, we might have a method called passFrizzbee which takes in two Dog objects, in this case, milo can be passed into this method as well because while Milo is Animal milo is also a Dog so now milo can pass a frizzbee to lassie which was another Dog object we created.
I hope I answered the second part of this question on sub typing correctly, it is entirely possible sub typing in haskell is not the same as a sub type in java!