Index
- 1. Model-View-Controller (MVC) Pattern
- 2. Commands as Methods and as Objects
- 3. Implementing Object-Oriented Language Features
- 4. Memory management in Java
1. Model-View-Controller (MVC) Pattern:
The Model-View-Controller (MVC) design pattern is a widely used pattern for creating user interfaces. It helps separate concerns into three interconnected components:
- Model: The core component, responsible for managing the data, logic, and rules of the application.
- View: The visual representation of the model’s data (UI).
- Controller: The intermediary between Model and View. It handles the user input and updates the Model accordingly.
How MVC Works:
- User Interaction: The user interacts with the View (UI), for example, by clicking a button.
- Controller Response: The Controller handles this input and translates it into an action for the Model.
- Model Update: The Model updates its data based on the action.
- View Update: Once the Model changes, the View updates itself to reflect the new data.
Example:
Imagine a simple text editor. The Model holds the text, the View displays the text, and the Controller handles user input like adding or deleting characters.
2. Commands as Methods and as Objects:
In object-oriented programming, commands can be handled in two primary ways:
- Commands as Methods: This is when you use methods (functions) to encapsulate a command or action.
- Commands as Objects: This is when you represent commands as separate objects (using the Command Pattern). Each command is represented as an object that encapsulates the action and the information needed to perform that action.
Command Pattern:
The Command Pattern is a behavioral design pattern that turns a request into a stand-alone object containing all the information about the request. It allows you to parameterize objects with operations, delay execution, queue operations, and support undoable operations.
Example :
Code example for Commands encapsulated as methods :
This version will encapsulate the logic for turning the light on and off inside a single RemoteControl
class, with methods representing commands instead of separate command classes.
How It Works:
- The
Light
class is the receiver with its own actions (turnOn()
andturnOff()
methods). - The
RemoteControl
class encapsulates the commands as methods (pressOnButton()
andpressOffButton()
), which internally call the appropriate methods on theLight
receiver. - In the
main
method, theRemoteControl
object is instantiated with aLight
object, and the button presses invoke the appropriate commands.
Key Differences:
- No Command Interface or Separate Command Classes: Instead of having separate
TurnOnCommand
andTurnOffCommand
classes that implement an interface, the commands are encapsulated as methods within theRemoteControl
class itself. - Direct Method Invocation: When the user presses a button on the remote, the corresponding method (
pressOnButton()
orpressOffButton()
) is directly invoked to perform the command. This simplifies the structure, but you lose some of the flexibility and extensibility that the command pattern provides.
When to Use This Approach:
- This method-based encapsulation works well for simpler use cases where you don’t need the flexibility to easily add new commands or change behavior at runtime.
- If you anticipate many different commands, or if the commands need to be passed around as objects (such as in a queue, or for undo/redo functionality), then the command pattern with separate command classes would be more appropriate.
Summary of Method Encapsulation vs. Command Pattern:
- Method Encapsulation: Simpler, direct method calls without needing separate classes. This works well for cases where you have fewer commands or don’t need to change command behavior dynamically.
- Command Pattern (previous example): More flexible as it decouples the request from the action, allowing for easier modification of behavior, dynamic assignment of commands, and additional features like undo/redo.
3. Implementing Object-Oriented Language Features:
This section explores some key language features that are part of OO programming:
-
Abstraction: Focuses on exposing only relevant details while hiding the complexity of the internal implementation.
- Example: Abstract classes and interfaces in Java.
-
Encapsulation: Bundles data (fields) and methods operating on the data into a single unit (class) and restricts access to some of the object’s components.
- Example: Declaring class members as
private
and providingpublic
getter/setter methods.
- Example: Declaring class members as
-
Polymorphism: The ability to treat objects of different classes in the same way, typically using inheritance or interfaces.
- Example: Method overloading and overriding.
-
Inheritance: Allows one class to inherit fields and methods from another, promoting code reuse.
- Example:
extends
keyword in Java.
- Example:
-
Composition: Involves building complex objects by combining simpler ones. Unlike inheritance, composition doesn’t involve a parent-child relationship.
- Example: A class having an instance of another class as a field.
Comprehensive code example:
- A base class (
Animal
) to represent shared characteristics and behavior (abstraction and inheritance). - Derived classes (
Dog
andCat
) to represent specific animals (inheritance and polymorphism). - Encapsulated data (like
name
andage
). - Use of polymorphism to demonstrate overriding behavior.
Explanation of OOP Pillars in this Program:
-
Encapsulation:
- The
name
andage
attributes in theAnimal
class are private, meaning they can only be accessed within the class itself. - To interact with these private attributes, getter and setter methods are used (
getName()
,getAge()
,setName()
,setAge()
), encapsulating the data and controlling how it’s accessed.
- The
-
Abstraction:
- The
Animal
class is an abstract class, meaning it provides a common blueprint for all animals, but we cannot create anAnimal
object directly. - It contains an abstract method
makeSound()
that must be implemented by all subclasses, defining a general behavior that can be customized by different types of animals.
- The
-
Inheritance:
- The
Dog
andCat
classes inherit from theAnimal
class, meaning they inherit its properties and behaviors (like theeat()
method) and can also provide their own specific behaviors. - Both
Dog
andCat
share common attributes and behavior, such asname
andage
, through inheritance fromAnimal
.
- The
-
Polymorphism:
- Method Overriding: The
Dog
andCat
classes override themakeSound()
method of theAnimal
class to provide their own specific implementations (barking for dogs and meowing for cats). - The program uses the same method (
makeSound()
), but its behavior changes based on the type of object (Dog
orCat
) that calls it. This demonstrates polymorphism.
- Method Overriding: The
How the Program Works:
- The
Animal
class provides a general definition of an animal with common attributes and behaviors. Dog
andCat
inherit fromAnimal
but override themakeSound()
method to provide behavior specific to each type.- The
main()
method creates aDog
and aCat
, accesses their encapsulated data using getters, and demonstrates polymorphism by calling the samemakeSound()
method on each, with different results depending on the object type.
4. Memory management in Java
Memory management is crucial in any software development process. In Java, memory is automatically managed by the Garbage Collector (GC), but it’s important to understand the underlying concepts.
The Java Memory Model (JMM) is a part of the Java runtime environment that defines how threads interact through memory, including rules on data storage and retrieval for consistent access. It also provides a framework for handling concurrent execution, ensuring the integrity and safety of data across threads, even on multi-core systems.
Java Memory Model Components
The JMM organizes memory into three main regions:
- Heap Memory
- Stack Memory
- Method Area
Let’s break down each component:
1. Heap Memory
- Purpose: Heap memory is the region where all objects and class-level variables are stored.
- Lifecycle: Data in the heap is accessible to all threads, making it ideal for storing data that needs to persist beyond the scope of a single method.
- Garbage Collection: Heap memory is managed by the garbage collector (GC), which automatically removes objects no longer in use to free up memory.
2. Stack Memory
- Purpose: Stack memory holds local variables and method calls specific to each thread, meaning each thread has its own stack.
- Lifecycle: When a method is invoked, a new stack frame is created, storing its local variables and reference pointers. Once the method completes, the stack frame is destroyed, freeing up memory automatically.
- Scope: Stack memory is not shared between threads, ensuring thread safety for local variables.
3. Method Area
- Purpose: Also known as MetaSpace in modern JVMs, the method area holds class metadata, static variables, constants, and method code.
- Lifecycle: Data here persists for as long as the class is loaded. It’s a shared space accessible to all threads.
Java Memory Model and Concurrency
The JMM specifies rules around visibility and ordering of variables across threads to avoid concurrency issues:
- Visibility: Ensures that changes made by one thread are visible to others. Java’s
volatile
keyword can enforce immediate visibility by instructing the JVM to directly access memory. - Ordering: Uses a technique called happens-before ordering, guaranteeing that actions in one thread occur in the right sequence relative to actions in other threads.
Java Garbage Collection (GC)
The garbage collector (GC) is responsible for automatic memory management, especially in the heap. The GC identifies objects that are no longer in use, deallocates them, and frees up memory to prevent memory leaks. Java’s garbage collection is performed in multiple phases, often classified into young generation and old generation memory spaces.
Memory Generation Breakdown
-
Young Generation:
- Divided into Eden Space and Survivor Spaces (S0 and S1).
- Eden Space: Newly created objects start here. When it fills up, a minor garbage collection is triggered to move objects that are still in use to one of the Survivor Spaces.
- Survivor Spaces (S0 and S1): Act as intermediate spaces for objects that survive a minor GC, moving between them until they’re old enough for the old generation.
-
Old Generation:
- Objects that survive multiple rounds in the young generation are promoted to the old generation.
- When the old generation fills up, a major garbage collection (or full GC) is triggered, which is more intensive and can impact application performance.
-
Permanent Generation (PermGen) / Metaspace:
- In older JVMs, PermGen was used to store class metadata, but this was replaced by Metaspace in Java 8 to provide a more flexible memory allocation strategy for metadata.
Types of Garbage Collection Algorithms
Java employs different garbage collection algorithms for optimizing memory management based on the application’s requirements:
- Serial GC:
- Best for single-threaded applications, as it uses a single thread for garbage collection.
- Parallel GC (Throughput Collector):
- Uses multiple threads for GC in the young generation, making it suitable for high-throughput applications.
- CMS (Concurrent Mark-Sweep) GC:
- Designed for low-pause applications; performs most GC work concurrently with application threads, reducing the time the application is paused.
- G1 (Garbage-First) GC:
- Designed for larger heap sizes and provides predictable pause times by prioritizing regions with the most garbage, which optimizes collection across both young and old generations.
Phases of Garbage Collection
Garbage Collection is typically carried out in three phases:
- Mark Phase: Identifies all reachable objects starting from the root objects, which are still accessible and in use.
- Sweep Phase: Removes or “sweeps” objects that are not reachable and therefore considered garbage.
- Compact Phase: Compacts the heap by moving objects to fill gaps, reducing fragmentation and optimizing memory layout.
How to Interact with the Garbage Collector
Java provides some control over garbage collection:
System.gc()
: A request to the JVM for garbage collection, though it’s only a suggestion, not a command.- Finalization: If an object overrides the
finalize()
method, it will be called before the object is collected, although this is rarely recommended in modern Java due to performance concerns.