Sunday 26 January 2014

OOP Design - Part 1 - Fundamentals

I hope, you have already read "Preface" of this post.  Also don't miss to refer corresponding example java code (not for production, illustrative purposes only) to understand each fundamental topic.

About Building Object Oriented System

  • Its all about Objects - Instantiating, Communicating, Managing, Extending, Monitoring…
  • In most of the cases, Everything is done by Developer.
  • What developers end up without knowledge of object oriented design principles and patterns? --- Answer is "Complex Code" – which is hard to maintain, extend and reuse. Because of,
    • Writing to much boilerplate
    • Duplication
    • Entangled interfaces
    • Complicated dependencies
    • Rigid, Fragile and Immobile code
ABC of Object Oriented Design and Responsibilities
  • OO Design
    • Identify classes and objects
    • Decide methods belong to what class/object and how they interact
  • Responsibilities
    • Assigned to classes/methods during design
    • Translation of responsibilities into classes/methods is influenced by the granularity of responsibility
    • Responsibilities are not same as methods, but methods fulfill responsibilities
    • Two Types of responsibilities - Doing & Knowing

Goal of a Object Oriented Design

  • Reusability, Flexibility, Extendibility, Maintainability...

Characteristics of Bad Design / Design Smell

Yes, designs or code can smell. They point to problems with the structure of code: class organization, relationships, collaborations/dependencies, responsibilities etc. Software OOP fundamentals and design principles represent a set of guidelines that helps us to avoid having a bad design.

Some of key characteristics of bad design are,
  • Rigidity = It is hard to change because every change affects too many other parts of the system. That means, difficult to add new features.
  • Fragility = When you make a change, unexpected parts of the system break. That means, unable to identify impact of the change.
  • Immobility = Code is hard to reuse in another application because it cannot be disentangled from the current application. That means, no reusability.
  • Viscosity = Going with the flow of bad practices already being present in the code.
  • Needless Complexity = the design adds additional structure that provides no direct benefit.
  • Opacity = It is hard to read and understand.  The code does not express its intent well.

OOP Fundamentals

Abstraction = Looking only at the information that is relevant at the time.
  • Abstraction is the process or result of generalization by reducing the information content of a concept or an observable phenomenon, typically in order to retain only information which is relevant for a particular purpose.
  • Functional abstraction - means that a function can be used without taking into account how the function is implemented.
  • Data Abstraction - means that data can be used without taking into account how the data are stored.

Encapsulation = Data hiding mechanism. (example code snippet)
  • The process of binding or wrapping the data and the codes that operates on the data into a single entity. This keeps the data safe from outside interface and misuse. One way to think about encapsulation is as a protective wrapper that prevents code and data from being arbitrarily accessed by other code defined outside the wrapper.
  • For example, if a field is declared private, it cannot be accessed by anyone outside the class, thereby hiding the fields within the class.

Inheritance = IS-A relationship between a superclass and its subclasses. (example code snippet)
  • The process where one object acquires the members of another; plus can have its own.
  • For example, Dog (subclass) is-a of type Animal (superclass). So Dog can inherit (reuse) members of Animal class;  plus it can have its own new behavior and properties.

Polymorphism = single interface multiple implementations. (example code snippet)
  • How Polymorphism is supported in Java? - In terms of interface, inheritance, method overloading and method overriding. (Method overloading and method overriding uses concept of Polymorphism in Java where method name remains same in two classes but actual method called by JVM depends upon object at run time and done by dynamic binding in Java. In case of overloading method signature changes while in case of overriding method signature remains same and binding and invocation of method is decided on runtime based on actual object. This facility allows Java programmer to write very flexibly and maintainable code using interfaces without worrying about concrete implementation. One disadvantage of using Polymorphism in code is that while reading code you don't know the actual type which annoys while you are looking to find bugs or trying to debug program. But if you do Java debugging in IDE you will definitely be able to see the actual object and the method call and variable associated with it.)
  • Where to use Polymorphism in code? - You should use super type in method argument, variable name and return type of method.
  • Parameteric Polymorphism in Java - Java started to support parametric polymorphism with introduction of Generic in JDK1.5. Collection classes in JDK 1.5 are written using Generic Type which allows Collections to hold any type of object in run time without any change in code and this has been achieved by passing actual Type as parameter. 

Delegation = hand over the responsibility for a particular task to another class or method. (example code snippet)
  • If you need to use functionality in another class but you do not want to change that functionality then use delegation instead of inheritance.
  • Classical example of delegation design principle is equals() and hashCode() method in Java. In order to compare two object for equality we ask class itself to do comparison instead of Client class doing that check. Benefit of this design principle is no duplication of code and pretty easy to modify behavior.

Aggregation = HAS-A relationship. (example code snippet)
  • Aggregation is an association represents a part of a whole relationship where a part can exist without a whole. It has a weaker relationship.
  • For example, If line-item HAS-A product, then a line item is a whole and product is a part. If a line item is deleted, then corresponding product needs not to be deleted.

Composition = HAS-A relationship, but restricted form of Aggregation. (example code snippet)
  • Composition is an association represents a part of a whole relationship where a part cannot exist without a whole. If a whole is deleted then all parts are deleted. It has a stronger relationship.
  • Favor Composition over Inheritance.
  • For example, if order HAS-A line-items, then an order is a whole and line items are parts. If an order is deleted then all corresponding line items for that order should be deleted.

Loose Coupling = Low dependencies between “artifacts” (classes, modules, components). (example code snippet)
  • There shouldn’t be too much of dependency between the modules, even if there is a dependency it should be via the interfaces and should be minimal.
  • Avoid tight-coupling for collaboration between two classes (if one class wants to call the logic of a second class, then they first class needs an object of second class it means the first class creates an object of second class).
  • Strive for loosely coupled design between objects that interact.
  • Inversion Of Control (IoC) / Dependency Injection (DI) - With DI objects are given their dependencies at creation time by some third party (i.e. Java EE CDI, Spring DI…) that coordinates each object in the system. Objects aren’t expected to create or obtain their dependencies—dependencies are injected into the objects that need them. The key benefit of DI—loose coupling.

High Cohesion = The code has to be very specific in its operations. (example code snippet)
  • The responsibilities/methods are highly related to class/module.
  • The term cohesion is used to indicate the degree to which a class has a single, well-focused responsibilities. Cohesion is a measure of how the methods of a class or a module are meaningfully and strongly related and how focused they are in providing a well-defined purpose to the system.  The more focused a class is, the higher its cohesiveness - a good thing.
  • A class is identified as a low cohesive class, when it contains many unrelated functions within it. And that what we need to avoid, because big classes with unrelated functions hamper their maintaining. Always make your class small and with precise purpose and highly related functions.


Few principles, every developer should always keep in mind and apply when writing code.

Interface based design = Coding to an interface, not to an implementation
  • One of the best practices that object oriented programmers should try to strive for is to write java classes to interfaces instead of concrete classes.
  • Writing to interfaces reduces coupling and gives a great flexibility in running the unit and integration tests without having to modify the client code whenever the implementation of a service component is changed.
  • It can achieve code reuse with the help of object composition.

DRY principle = Don't repeat yourself
  • Software development principle to reduce repetition of information of all kinds.
  • Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
  • Avoid copy-paste of code. Otherwise change in the code would have to be made in all the places where its been copied.
  • Don't write duplicate code for "application logic", instead abstract common things in one place.
  • For example - If you use a hardcoded value more than one time consider making it public final constant. If you have block of code in more than two place consider making it a separate method.

KISS principle = Keep it simple, stupid / keep it simple and straightforward
  • Simplicity should be the a goal of design and unnecessary complexity should be avoided.
  • For example - If there is a need of grate manipulations on collections, then don't write your own complex custom implementation. If you like the "Function" style, maybe make use of the proven Guava library (which has the Function interface and many helper methods that work with them on collections). That is DRY (because you don't repeat yourself, and re-use code that already exists), and still KISS (because those are well understood patterns).

YAGNI principle = You aren't gonna need it
  • A principle of extreme programming (XP) that states a programmer should not add functionality until deemed necessary.
  • Don't be tempted to write code that is not necessary at the moment, but might be in the future.
  • Recommended to be used in combination with several other practices, such as continuous refactoring, continuous automated unit testing and continuous integration.
  • See also - Over-engineering

AOP = Aspect Oriented Programming
  • A programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns (e.g. logging, exceptional handling, caching…). Identify the aspects of your application that vary and separate them from what stays same.
  • AOP is a concept and as such it is not bound to a certain programming language or programming paradigm. The Java implementation of AOP is called AspectJ. Or Spring AOP can be used.


Also Refer:

No comments:

Post a Comment