• Home
  • Quick Bytes
  • Algorithms
  • Java
  • iOS
  • Android
  • Certifications
  • About Me

Lets Code Them Up!

  • Clean Architecture – Chapter 3 | Paradigm Overview

    February 18th, 2023

    As per author there are three paradigms in programming – 

    1. Structured Programming
    2. Object Oriented Programming
    3. Functional Programming

    Lets’s go through each of them briefly as subsequent chapters go in detail on them.

    Structured Programming

    Structured programming imposes discipline on direct transfer of control

    Robert Martin

    This paradigm was discovered last, but was the first to be adopted. It was discovered by Dijsktra. It removes the use of unrestrained GOTO statements. Goto statements were used to transfer control to another part of code, and once that finished, there would be another go to statement to return back. This would create unnecessary overhead in programming. Also, adversely impacting readability of code. He replaced goto with if/then/else and do/while/until, or more specifically what we now call conditional statements and loops.

     

    Object Oriented Programming

    Object-oriented programming imposes discipline on indirect transfer of control

    Robert Martin

    This paradigm was second to be discovered but was adopted after structured programming. It was discovered by Johan Dahl and Kristen Nygaard. They moved the function call stack to heap, which allowed the reuse of local variables by multiple functions. (Each thread has its own stack but multiple threads share the heap memory) Now in modern programming we have constructors in a class to initialize objects and instance variables. These instance variables are accessible to all the methods in the class. Thereby decreasing unnecessary function calls to pass those instance variables. 

     

    Functional Programming

    Functional programming imposes discipline on assignment

    Robert Martin

    This paradigm was the first to be discovered but last to be adopted. It was discovered by Alonzo Church. This is based on lambda functions in mathematics. Lambda functions are based on the assumption that values of the symbols do not change (Immutability). And most of the functional programming languages have no assignment statement. They do allow changing the value but under strict conditions.

    Summary

    Most of the modern programming languages today follow all three paradigms in some way. For example, Java, primarily object-oriented language, not long ago from Java 8 implemented functional interfaces to allow for functional programming. Another great example is Javascript. We will see Structured programming paradigm in next post and learn how modern languages heavily use it.

    Thanks for stopping by! Hope this gives you a perspective on software paradigms. Post comments to start a discussion. See you in the next post.

  • Clean Architecture – Chapter 2

    February 11th, 2023

    Two values that a software system provides – Behavior and Structure.

    Behavior – Developers are hired with the intent to make the machine behave in a way that makes the client work better or saves money.

    Structure – Software must be designed to be soft, ie easy to change. 

    Which of these two provide more value?

    Let’s think we have two systems – 

    1. First system is working but is impossible to change. If a new requirements come, it will be impossible to make it work and therefore will become useless
    2. Second system is not working but is very easy to change. It can be modified to be in working condition and continue functioning with new requirements

    So, the structure/architecture is the more important value. 

    However often times, in order to deliver quickly, we compromise on the architecture of the system and end up spending more cost and time later when new requirements need to be added.

    Eisenhower’s matrix

     

    Eisenhower’s matrix

    As we can see, eisenhower had a matrix in which he divided problems – 

    1. Important and urgent
    2. Important and not urgent
    3. Not important and urgent
    4. Not important and not urgent

    Software Behavior is urgent but can be important or not important. So it qualifies for 1 and 3.

    Software architecture is important but not urgent. So it qualifies for 2.

    Most times, managers and developers prioritize 3 over 1, focusing on features which are not important instead of the important and urgent. This leads to ignoring important architecture of system in favor of not important features. We as software developers and software architect should fight for the architecture of the system to implement the system in right way from start.

    Thanks for stopping by! Hope this gives you a perspective on values software system provides and which one is important and why. Post comments to start a discussion. See you in the next post.

  • Abstract Factory Pattern

    February 4th, 2023

    In the last two posts on Factory Pattern using Factory method – part 1 and part 2, we went through how factory method works, using the toyota car factory example. Let’s continue to build on that example and understand the Abstract Factory Pattern. 

    Using the factory method, we implemented our interfaces CarFactory and ToyotaCar and their concrete implementations for Toyota. But the toyota leaders found out that their factories in California and Washington are not using the genuine toyota parts while assembling Toyota cars, thereby degrading quality of the cars. And so toyota has decided to create a factory for genuine toyota parts that produces these parts and sends them to the car factories. 

    Let’s call the parts factory ToyotaPartsFactory. CaliforniaToyotaPartsFactory and WashingtonToyotaPartsFactory will now supply these parts to the CaliforniaToyotaCarFactory and WashingtonToyotaCarFactory respectively

    public interface ToyotaPartsFactory {
    
           public Engine createEngine();
           public Wheels wheels();
           public Seats seats();
    }
    
    Abstract Factory Pattern using Toyota Parts Factory example
    public class CaliforniaToyotaPartsFactory implements ToyotaPartsFactory {
     
          public Engine createEngine() {
                return V8Engine();
          }
    
          public Wheels createWheels() {
                return AlloyWheels();
          }
    
          public Seats createSeats() {
                 return LeatherSeats()l
          }
    }
    
    

    Our new ToyotaCar object would now have an abstract method called assembleParts. This would be implemented by the subclasses to use the correct parts while assembling the car. In our concrete CarFactories, we will now be passing the respective ToyotaPartFactories. As shown below, in the CaliforniaToyotaPartsFactory we are passing the CaliforniaToyotaPartsFactory.

    public abstract class ToyotaCar {
           String modelName;
           Engine engine;
           Wheels wheels;
           Seats seats;
    
           abstract void assembleParts();
    
           void polish() {
                System.out.println("Polishing "+modelName+" car";
           }
    }
    
    public class Sienna extends ToyotaCar {
            ToyotaPartsFactory toyotaPartsFactory;
    
            public Sienna(ToyotaPartsFactory toyotaPartsFactory) {
                 this.toyotaPartsFactory = toyotaPartsFactory;
             }
    
             void assembleParts() {
                  System.out.println("Assembling "+modelName+" car";
                  engine = toyotaPartsFactory.createEngine();
                  wheels = toyotaPartsFactory.createWheels();
                  seats = toyotaPartsFactory.createSeats();
             }
    }
    
    public class CaliforniaToyotaCarFactory extends CarFactory {
            ToyotaCar createCar(String model) {
                   ToyotaCar car = null
            ToyotaPartsFactory toyotaPartsFactory = new CaliforniaToyotaPartsFactory();
            if(model.equals("sienna") {
                return new Sienna(toyotaPartsFactory);
            } else if(model.equals("highlander") {
                return new HighLander(toyotaPartsFactory);
            } else if(model.equals("prius") {
                return new Prius(toyotaPartsFactory);
            else {
                return null;
            }
         }
    }
    

    We now have the power to create a family of different part objects. That’s what an Abstract Factory does. It gives an interface for creating a factory of products. The second advantage is decoupling. Our code for creating products (ToyotaCar) is decoupled from the code for creating the other line of product families. It opens up the architecture for creating different types of factories needed, with each decoupled from others.

    Abstract Factory Pattern

    Thanks for stopping by! Hope this gives you a perspective on Abstract Factory pattern. Post comments to start a discussion. See you in the next post.

  • Factory Pattern using Factory Method – Part 2

    January 28th, 2023

    Continuing on the example of ToyotaCarFactory from our last post Factory Pattern – Part 1, the main aim of the ToyotaCarFactory is to fulfill an order for a ToyotaCar. There are multiple models of Toyota and the factory should manufacture them all.

    Our Creator is the CarFactory, having the createCar() factory method which would hold the object instantiation part. ToyotaCarFactory is our concrete creator class which would be responsible for creating the different ToyotaCar objects by providing an implementation of createCar() method. 

    As we can see below in the CarFactory code, createCar is our factory method, it is abstract and so will get implemented in subclasses.

    public abstract class CarFactory {
    
         public ToyotaCar orderCar(String model) {
                
                ToyotaCar car;
                car = createCar(model);
                car.assembleParts();
                car.polish();
    
                return car;
          }
          protected abstract ToyotaCar createCar(String model);
    }
    

    CaliforniaToyotaCarFactory and WashingtonToyotaCarFactory are our two factories in California and Washington respectively. CaliforniaToyotaCarFactory produces ToyotaCar objects of type Sienna, Highlander and Prius. WashingtonToyotaCarFactory produces ToyotaCar objects of type Sienna, Highlander, Tacoma. Now if Toyota decides to open another factory in Texas, they will just need to implement TexasToyotaCarFactory and have the concrete objects of the models that that factory will produce. See, how easy it is to add new factories without modifying the already written code. 

    public class CaliforniaToyotaCarFactory extends CarFactory {
         ToyotaCar createCar(String model) {
            if(model.equals("sienna") {
                return new Sienna();
            } else if(model.equals("highlander") {
                return new HighLander();
            } else if(model.equals("prius") {
                return new Prius();
            else {
                return null;
            }
        } 
    }
    
    
    public class WashingtonToyotaCarFactory extends CarFactory {
         ToyotaCar createCar(String model) {
            if(model.equals("sienna") {
                return new Sienna();
            } else if(model.equals("highlander") {
                return new HighLander();
            } else if(model.equals("tacoma") {
                return new Tacoma();
            else {
                return null;
            }
        } 
    }
    

    As we can see, the concrete classes which extend out CarFactory interface are actually creating new ToyotaCar objects, ie, subclasses are deciding which objects to initialize.

    Let’s see how our ToyotaCar and it’s subclasses would look like. 

    public abstract class ToyotaCar {
           String modelName;
           String engine;
           String wheels;
           String seats;
    
           void assembleParts() {
                System.out.println("Assembling "+modelName+" car";
           }
    
           void polish() {
                System.out.println("Polishing "+modelName+" car";
           }
    }
    
    public class Sienna extends ToyotaCar {
            
           public Sienna() {
               modelName = "Sienna";
               engine = "XXX";
               wheels = "four";
               seats = "leather";
          }
    }
    
    public class Highlander extends ToyotaCar {
            
           public Highlander() {
               modelName = "Highlander";
               engine = "XXX";
               wheels = "four";
               seats = "leather";
          }
    }
    

    Let’s group them all together. To order a Sienna from Califonia factory of Toyota, we will need to initialize the CaliforniaToyotaCarFactory and then call the orderCar method on it with “sienna” as parameter. This would in turn call the createCar implementation of CaliforniaToyotaCarFactory, which will initialize the Sienna object. 

    public class ToyotaTestDrive {
    
    public static void main(String[] args) {
          CarFactory calToyotaCarFactory = new CaliforniaToyotaCarFactory();
          CarFactory washToyotaCarFactory = new WashingtonToyotaCarFactory();
    
          ToyotaCar car = calToyotaCarFactory.orderCar("sienna");
    System.out.println("Ordered Car "+car.getName());
    
          ToyotaCar car = washToyotaCarFactory.orderCar("tacoma");
    System.out.println("Ordered Car "+car.getName());
    

    In next post we will see, how Abstract Factory Pattern work.

  • Factory Pattern using Factory Method- Part 1

    January 22nd, 2023

    Why the need for factory pattern?

    Let’s take example of a ToyotaCarFactory, the main aim of the ToyotaCarFactory is to fulfill an order for a ToyotaCar. There are multiple models of Toyota and the factory should manufacture them all.

    The orderCar method would look something like this – 

    ToyotaCar orderCar(String model)
    {
        ToyotaCar car;
    
        if(model.equals("sienna") {
           car = new SiennaToyotaCar();
        } else if(model.equals("highlander") {
           car = new HighLanderToyotaCar();
        } else if(model.equals("prius") {
           car = new PriusToyotaCar();
        } 
    
        car.assembleParts();
        car.polish();
        car.testDrive();
    }
    
    

    If Toyota decided to launch three other methods, the object instantiation part would keep on increasing. And we would need to change it, make sure nothing breaks, add the code to correct part. Our code is not closed for modification, as every time new type of toyota car is added, we have to open this and modify it. 

    If instead we would have implemented against a CarFactory interface, then we would have given the responsibility of instantiating the required objects to the subclasses.  And say other car manufacturers want to use the same CarFactory, we could easily add new concrete subclasses without causing changes to existing ones. 

    That’s the advantage of coding to interfaces as opposed to coding to concrete implementation. Your code is following the principle of “Open for extension, closed for modification”.

    Factory Pattern

    Creator is the interface which has the factory method. But the subclasses which implement the factory method actually create the Product objects.

    Example

    Let’s use an example to better understand this pattern.

    Example of Factory Pattern using Toyota Car manufacturing

    Continuing on our Car manufacturing example, our Creator is the CarFactory, having the createCar() factory method which would hold the object instantiation part. ToyotaCarFactory is our concrete creator class which would be responsible for creating the different ToyotaCar objects by providing an implementation of createCar() method. 

    We will see a sample implementation in the following post.

  • Decorator Pattern

    January 15th, 2023

    What is Decorator Pattern?

    Decorator pattern attaches additional responsibilities to an object dynamically (at runtime). It provides flexible alternative to subclassing for extending functionality. 

    It involves a set of Decorator classes that are used to wrap concrete components. Decorator classes mirror the object they wrap and change the behavior of concrete components by adding new functionalities.

    Let’s use an example to understand this pattern –

    We have our Pizza delivery service, we offer basic pizza with different types of bases and varieties of toppings like veggies, protein, extra cheese etc. Each different topping has it’s own price which adds up to the final cost. 

    Say we implement this using inheritance, we would have our main object Pizza with some functionality and then we will have separate classes for different pizza on the menu, example one for cheese pizza, veggie delight pizza, etc.

     

    Pizza object

    The main drawbacks here would be that

    1. if any other topping is added, we will have to go an update Pizza’s cost method,
    2. Add it as variable with it’s accessors to the Pizza class
    3. If cost of any topping changes/discounts come, we would have to go and change it in Pizza class.
    4. All the different pizza types would not need all the toppings, example cheese pizza would not need veggies/protein, etc.

    Let’s see how we can have an extensible solution using Decorator pattern – 

    We will have our main Pizza object and our Toppings decorator object. CheesePizza is our Concrete component example. We have our ToppingsDecorator which is extended by different toppings that we add. We can see the following advantages –

    1. if you want to add a discount on the pizza, you can just create another decorator Discount on the pizza object.
    2. If prize of any topping changes, we just need to go to that concrete decorator and update the cost.

     

    Pizza object using Decorator Pattern

    Open-Closed Design Principle and Decorator Pattern

    Open-Closed principle states that classes should be open for extension and closed for modification. If we find that our existing code needs new logic, example new behavior like adding discount, decorator pattern allows us to add that without modifying the existing object. 

    Drawbacks

    • It could result in lot of small decorator objects, increasing number of objects and complexity

    Real World Examples

    • Java I/O package classes 
    • Java Streams API 

     

←Previous Page
1 … 6 7 8 9 10 … 22
Next Page→

Proudly powered by WordPress

 

Loading Comments...