JAVA-202: Sprint Summary

Modified on Thu, 18 Jul at 8:06 PM

Sprint Summary for JAVA-202



TABLE OF CONTENTS



Topic 1: Object-Oriented Programming


What is it? 

Object Oriented Programming (OOP) is a programming paradigm based on the concept of objects, which can contain data and code to manipulate that data.

Where is it used? OOP is used in software development to create modular and reusable code.

How is it used?

  • Classes and objects: Define classes as blueprints and create objects as instances.

  • Encapsulation: Bundle data and methods within classes.

  • Inheritance: Create new classes from existing ones.

  • Polymorphism: Use a single interface to represent different underlying forms.

Example:

class Dog {

    private String name;

    private int age;



    public Dog(String name, int age) {

        this.name = name;

        this.age = age;

    }



    public void bark() {

        System.out.println(name + " is barking");

    }

}


Takeaways / Best Practices:

  • Use OOP principles to enhance code modularity and reusability.
  • Follow encapsulation to protect object integrity.
  • Apply inheritance and polymorphism judiciously to avoid complexity.



Topic 2: UML Class Diagrams


What is it? 

UML (Unified Modeling Language) Class Diagrams are visual representations of classes, their attributes, methods, and relationships.

Where is it used? 

UML Class Diagrams are used in software design to model the static structure of a system.

How is it used?

  • Classes are represented with rectangles.

  • Relationships like inheritance, association, and aggregation are shown with lines and arrows.

  • Attributes and methods are listed within class rectangles.

Takeaways / Best Practices:

  • Use UML Class Diagrams for clear and structured system design.

  • Keep diagrams simple and focused on relevant details.

  • Regularly update diagrams to reflect changes in the codebase.


Topic 3: Class Relationships and Cardinality


What is it? 

Class relationships describe how classes interact with each other. Cardinality specifies the number of instances involved in the relationship.

Where is it used? 

Class relationships and cardinality are used in system design to model interactions between classes.

How is it used?

  • Associations: Represents relationships between classes.

  • Aggregation: Represents a whole-part relationship.

  • Composition: Represents a stronger whole-part relationship.

  • Cardinality: Indicates the number of instances (e.g., one-to-one, one-to-many).

Example:

  • One-to-Many: A Library has many Books.

  • Composition: A House has Rooms (Rooms cannot exist without the House).

Takeaways / Best Practices:

  • Clearly define class relationships to improve system understanding.
  • Use appropriate cardinality to accurately represent interactions.
  • Prefer composition over inheritance for flexibility and reusability.



Topic 4: Object Methods


What is it? Object methods are methods defined in the Object class, which is the superclass of all classes in Java. These methods provide basic operations that can be performed on any object.

Where is it used? Object methods are used in every Java class, as they inherit from the Object class.

How is it used?

  • Methods include toString()equals()hashCode()clone()finalize()getClass()notify()notifyAll(), and wait().

Example:

@Override

public String toString() {

    return "Dog{name='" + name + "', age=" + age + "}";

}



@Override

public boolean equals(Object obj) {

    if (this == obj) return true;

    if (obj == null || getClass() != obj.getClass()) return false;

    Dog dog = (Dog) obj;

    return age == dog.age && Objects.equals(name, dog.name);

}



@Override

public int hashCode() {

    return Objects.hash(name, age);

}


Takeaways / Best Practices:

  • Override toString() for meaningful object representation.

  • Implement equals() and hashCode() for correct object comparison and use in collections.

  • Use clone() carefully, considering deep vs. shallow copies.


Topic 5: Single Responsibility Principle


What is it? The Single Responsibility Principle (SRP) states that a class should have only one reason to change, meaning it should have only one job or responsibility.

Where is it used? SRP is used in software design to promote high cohesion and low coupling.

How is it used?

  • Define classes with a single responsibility.

  • Refactor classes that have multiple responsibilities into smaller, focused classes.

Example: A class handling both data access and UI logic should be split:

  • DataAccess class for database operations.

  • UserInterface class for UI logic.

Takeaways / Best Practices:

  • Adhere to SRP to improve code maintainability and readability.
  • Regularly review and refactor code to ensure compliance with SRP.
  • Use SRP in conjunction with other SOLID principles for robust design.



Topic 6: Open-Closed Principle


What is it? The Open-Closed Principle (OCP) states that software entities should be open for extension but closed for modification.

Where is it used? OCP is used to enhance system extensibility and maintainability.

How is it used?

  • Use interfaces and abstract classes to allow new functionality without altering existing code.

  • Extend existing classes to add new behaviors.

Example:

abstract class Shape {

    abstract void draw();

}



class Circle extends Shape {

    void draw() {

        System.out.println("Drawing Circle");

    }

}



class Square extends Shape {

    void draw() {

        System.out.println("Drawing Square");

    }

}


Takeaways / Best Practices:

  • Follow OCP to reduce code changes and potential bugs.

  • Use abstraction to allow extensibility.

  • Regularly refactor code to keep it aligned with OCP.


Topic 7: Liskov Substitution Principle


What is it? The Liskov Substitution Principle (LSP) states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.

Where is it used? LSP is used in inheritance hierarchies to ensure that derived classes can be substituted for base classes.

How is it used?

  • Ensure subclasses adhere to the behavior expected by the base class.

  • Avoid overriding methods in a way that violates the base class contract.

Example:

class Bird {

    void fly() {

        System.out.println("Bird is flying");

    }

}



class Ostrich extends Bird {

    void fly() {

        throw new UnsupportedOperationException();

    }

}


Here, Ostrich violates LSP because it cannot fly.

Takeaways / Best Practices:

  • Design subclasses to be substitutable for their base classes.

  • Adhere to the base class's expected behavior in subclasses.

  • Use LSP to create robust and maintainable class hierarchies.


Topic 8: Interface Segregation Principle


What is it? The Interface Segregation Principle (ISP) states that clients should not be forced to depend on interfaces they do not use.

Where is it used? ISP is used in interface design to promote the creation of smaller and more specific interfaces.

How is it used?

  • Define multiple specific interfaces rather than a single general-purpose interface.

  • Ensure that classes implement only the interfaces relevant to them.

Example:

interface Printer {

    void print();

}



interface Scanner {

    void scan();

}



class AllInOnePrinter implements Printer, Scanner {

    public void print() {

        System.out.println("Printing...");

    }



    public void scan() {

        System.out.println("Scanning...");

    }

}



class SimplePrinter implements Printer {

    public void print() {

        System.out.println("Printing...");

    }

}


Takeaways / Best Practices:

  • Apply ISP to keep interfaces focused and manageable.

  • Avoid creating monolithic interfaces that force unnecessary implementations.

  • Use ISP to enhance code modularity and flexibility.


Topic 9: Dependency Injection Principle


What is it? The Dependency Injection Principle (DIP) is a design pattern that implements Inversion of Control (IoC) to achieve loose coupling by injecting dependencies rather than creating them within the class.

Where is it used? DIP is used in software design to promote dependency management and code flexibility.

How is it used?

  • Use constructors, setters, or interfaces to inject dependencies.

  • Leverage dependency injection frameworks like Spring.

Example:

class Engine {

    void start() {

        System.out.println("Engine started");

    }

}



class Car {

    private Engine engine;



    public Car(Engine engine) {

        this.engine = engine;

    }



    void drive() {

        engine.start();

        System.out.println("Car is driving");

    }

}


Takeaways / Best Practices:

  • Use dependency injection to enhance code modularity and testability.
  • Prefer constructor injection for mandatory dependencies.
  • Apply DIP in conjunction with IoC frameworks for robust application design.




Topic 10: Factory Method Pattern


What is it? The Factory Method Pattern is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created.

Where is it used? It is used when the exact type of object to be created cannot be determined until runtime.

How is it used?

  • Define a factory method in a base class and let subclasses override it to create specific objects.

Example:

abstract class AnimalFactory {

    abstract Animal createAnimal();



    public void describeAnimal() {

        Animal animal = createAnimal();

        animal.describe();

    }

}



class DogFactory extends AnimalFactory {

    @Override

    Animal createAnimal() {

        return new Dog();

    }

}



class CatFactory extends AnimalFactory {

    @Override

    Animal createAnimal() {

        return new Cat();

    }

}


Takeaways / Best Practices:

  • Use the Factory Method Pattern to encapsulate object creation and promote loose coupling.

  • Ensure subclasses provide specific implementations for the factory method.

  • Combine with other patterns, like Singleton, for enhanced functionality.


Topic 11: Builder Pattern

What is it? The Builder Pattern is a creational design pattern that allows for the step-by-step construction of complex objects.

Where is it used? It is used when an object requires multiple steps to be created or when the creation process is complex.

How is it used?

  • Use a builder class with methods to set properties and a build method to create the object.

Example:

class Car {

    private String make;

    private String model;

    private int year;



    private Car(Builder builder) {

        this.make = builder.make;

        this.model = builder.model;

        this.year = builder.year;

    }



    public static class Builder {

        private String make;

        private String model;

        private int year;



        public Builder setMake(String make) {

            this.make = make;

            return this;

        }



        public Builder setModel(String model) {

            this.model = model;

            return this;

        }



        public Builder setYear(int year) {

            this.year = year;

            return this;

        }



        public Car build() {

            return new Car(this);

        }

    }

}


Takeaways / Best Practices:

  • Use the Builder Pattern for creating objects with multiple optional parameters.

  • Ensure the builder class is separate from the object being constructed.

  • Use method chaining in the builder class for readability and ease of use.


Topic 12: Singleton Pattern

What is it? The Singleton Pattern is a creational design pattern that ensures a class has only one instance and provides a global point of access to it.

Where is it used? It is used when only one instance of a class is needed, such as in configuration or logging.

How is it used?

  • Make the constructor private and provide a static method to get the instance.

Example:

public class Singleton {

    private static Singleton instance;



    private Singleton() {}



    public static Singleton getInstance() {

        if (instance == null) {

            instance = new Singleton();

        }

        return instance;

    }

}


Takeaways / Best Practices:

  • Use the Singleton Pattern to ensure a class has only one instance.
  • Be mindful of thread safety when implementing the Singleton Pattern.
  • Consider using lazy initialization to create the instance only when needed.






Happy Learning!

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article