L
LLLOS.ai
Learn
L

Chapter 5 — Objects

Class 11 · Computer Science

Overview

This unit introduces objects as the central idea of object-oriented programming (OOP). It shows how real-world entities are modelled using classes (blueprints) and objects (instances) that combine data and behaviour. The unit explains attributes, methods, constructors, access control, static members and object lifecycle. Core OOP principles — encapsulation, inheritance, polymorphism and abstraction — are presented with practical guidance on when and how to apply them. You will learn to represent relationships between objects such as association, aggregation and composition, and how objects communicate by message passing (method invocation). The unit also introduces UML class diagrams to document designs, basic design principles like single responsibility and separation of concerns, and simple design patterns (Factory and Observer). Together, these topics prepare students to design modular, reusable and maintainable programs. Mastery of objects is important because most modern programming languages and frameworks use object-oriented concepts, and good object design improves code clarity, testing and long-term maintenance. The unit gives both conceptual foundations and practical examples that prepare you for writing and analysing object-oriented programs in the language you use at school.

Learning Objectives

  • Explain the idea of modelling real-world entities as objects and classes.
  • Define and identify attributes, methods, objects and classes in simple programs.
  • Apply encapsulation and access specifiers to protect object data.
  • Demonstrate inheritance and reuse of code across related classes.
  • Use polymorphism to write flexible code that works with different object types.
  • Write and use constructors to initialise objects and describe object lifecycle.
  • Distinguish between association, aggregation and composition in object relationships.
  • Interpret and draw basic UML class diagrams for simple systems.
  • Apply basic design principles that improve modularity and maintainability of object-oriented code.

Topics in this chapter

15 topics · tap a topic title to jump straight to it.

💻1

Introduction to Objects and Classes

Understanding the idea
Objects are a way to represent things from the real world inside a computer program. Each object groups two parts: state (the data that describes it) and behaviour (the operations it can perform). For example, a Bicycle object may have state like colour and gearCount and behaviour like pedal() and applyBrake().

Classes as blueprints
A class is the template that defines what attributes and methods objects of that type will have. Think of a class as the plan for a house and objects as the houses built from that plan. The class defines the layout and components; each object uses that layout but can have different values for its attributes.

Why objects help
When building larger programs, grouping related data and functions inside classes keeps code organised. Instead of writing separate functions and loose data, classes provide a consistent way to bundle everything related to a concept. This improves readability and reduces repeated code because behaviour common to many objects can be placed in one class definition.

Instances and identity
Creating an object from a class is called instantiation. Each instance has its own identity and attribute values. Two Bicycle objects may both be of class Bicycle but have different colours and gear settings. The language runtime keeps track of each object separately.

Classes and modelling
When designing a program, choose classes that represent clear entities in the problem domain: Student, BankAccount, Book, Sensor, etc. For each class, decide which attributes should be stored and which actions should be provided as methods. Keeping classes focused helps later changes and testing.

Code organisation and reuse
Classes promote reuse: once a class is written and tested, it can be used in many places or by many programs. Libraries are collections of classes designed to solve common tasks. By learning to think in terms of objects and classes, you prepare for larger projects and industry-standard programming patterns.

📌 Examples
  • Student class with attributes rollNumber, name and methods attendClass(), submitAssignment().
  • BankAccount class storing balance and accountNumber, with methods deposit(amount), withdraw(amount).
  • Lamp class with attribute isOn and methods switchOn(), switchOff() to change state.
🧮 Formulas
  1. Class: blueprint defining attributes and methods.
  2. Object (instance): a concrete occurrence of a class with specific attribute values.
📊 Visual ideas
A simple box showing class name at top, attributes in the middle compartment and methods in the lower compartment (basic UML class box).
💻2

Attributes (State) and Methods (Behaviour)

Attributes: what objects hold
Attributes (also called fields or properties) are the values that describe an object. They represent the object's state. Attributes may be simple types such as numbers or text, or they may be references to other objects. When you design a class, list the essential attributes required to describe each instance. For example, a Rectangle class needs length and breadth to describe its shape.

Methods: what objects do
Methods are functions defined inside a class that describe how an object behaves. Methods can read or change attributes and perform tasks. A method could compute a result (like area()), change internal state (like deposit()), or coordinate actions across multiple objects (like transfer()). Methods form the public interface through which other parts of the program interact with the object.

Instance vs class members
Instance attributes belong to each object separately: every object has its own copy. Class-level (static) attributes are shared across all objects of the class: changing a static attribute affects every instance. Decide whether a value should be shared (like a global constant) or unique to each instance when designing attributes.

Parameters and return types
Methods can accept parameters to receive input and can return values. When writing a method, specify what it needs from the caller and what it will produce. Keep method responsibilities focused: a method should do one clear task and have a simple contract (inputs and outputs).

Visibility and access
Good design keeps attributes private and offers public methods (getters and setters) when outside access is necessary. This prevents external code from putting the object into an invalid state. Methods that expose behaviour can validate inputs and maintain invariants.

Design considerations
Avoid exposing internal details unnecessarily. Use methods to provide controlled access. When an attribute can be computed from others, consider providing a method instead of storing redundant data. Keep methods small and testable so their effects are clear and predictable.

📌 Examples
  • Rectangle class with attributes length and breadth and method area() returning length × breadth.
  • Clock class with attribute currentTime and methods setTime(h,m), getTime() and tick() that increments time.
  • Account class with private attribute balance and public methods deposit(amount) and withdraw(amount) that validate amounts.
🧮 Formulas
  1. area of rectangle = length × breadth
📊 Visual ideas
Diagram of a class box showing attributes (length, breadth) and method area() with arrows showing method uses attributes.
📊3

Encapsulation and Data Hiding

What encapsulation means
Encapsulation bundles an object's data and the methods that operate on that data into a single unit — the class. Data hiding is the practice of preventing external code from accessing or modifying the internal state directly. Together, these ideas protect the object’s integrity and define clear interfaces for interaction.

Why hide data?
Allowing outside code to change attributes directly leads to fragile programs. Without control, attributes may get invalid values or inconsistent combinations. By exposing only methods that enforce validation rules, the class maintains its invariants. For example, an Account class should ensure balance never becomes negative unless allowed by overdraft rules; the withdraw() method enforces this.

Getters and setters
Getters and setters are public methods used to read and write private attributes. Setters validate input before assignment and can trigger side effects (such as updating derived values). Getters can format or compute values on demand rather than exposing raw internal data. Use them when external access is necessary, but do not create them reflexively for every attribute—only expose what must be accessed externally.

Encapsulation helps change without breaking
If internal representation needs to change (for example, storing temperature in Kelvin instead of Celsius), encapsulation allows the change to be local to the class. External code calling getTemperature() and setTemperature() can remain unchanged because the class translates internally. This reduces coupling and helps in refactoring.

Practical patterns
1) Keep attributes private unless there is a strong reason to make them public. 2) Provide methods that perform meaningful operations rather than exposing low-level state. 3) Use immutable objects where possible: if an object’s state is fixed after creation, many bugs are avoided. 4) Validate inputs in setters and constructors to keep objects consistent from creation.

Examples and caution
Overuse of getters and setters can still expose internal structure indirectly. Aim for behaviour-oriented interfaces: methods that do high-level tasks (transfer(), computeAverage(), render()) rather than simple read/write pairs for every attribute.

📌 Examples
  • Making balance private in an Account class and providing deposit() and withdraw() methods to control changes.
  • A Student class that validates roll number format inside the setter method before storing it.
  • A Temperature class storing value in Celsius privately and offering getFahrenheit() to present in Fahrenheit.
📊 Visual ideas
A block diagram showing an object with private data and public methods; arrows from external code go to methods but not directly to data.
💻4

Constructors and Object Initialization

Role of constructors
Constructors are special methods invoked when an object is created to initialise its attributes and prepare it for use. They set up a valid internal state and may allocate resources needed by the object. A well-designed constructor leaves the object ready to use immediately after creation.

Default and parameterised constructors
A default constructor takes no arguments and sets attributes to standard initial values. A parameterised constructor accepts inputs so objects can start with custom state. Offering both styles increases flexibility: clients can choose simple defaults or supply precise initial values.

Overloading constructors
Many languages support multiple constructors with different parameter lists (overloading). For example, a Rectangle class may have a default constructor setting both sides to 1, another constructor accepting length and breadth, and a copy constructor that creates a new object from an existing one.

Best practices for constructors
Keep constructors simple and avoid heavy work such as long-running I/O or network calls because these can make object creation fail or slow. If object creation is complex or may fail, use factory methods that can return error values or manage creation steps. Validate constructor parameters and throw exceptions or return errors for invalid inputs to prevent creation of invalid objects.

Chaining and delegation
Constructor chaining allows one constructor to call another to reduce code duplication when several constructors share initialisation logic. This keeps initialisation centralised and easier to maintain. Inheritance requires attention: the parent class constructor usually runs before the child class constructor to initialise inherited state.

Destructors and resource cleanup
Some languages provide destructors or finalisers that run when an object is destroyed to free resources. In languages with automatic garbage collection, finalisers are not deterministic in timing, so explicit close/dispose methods are preferred for non-memory resources such as files or sockets. Use try-finally or language-specific constructs to ensure deterministic cleanup.

📌 Examples
  • Book class with constructor Book(title, author, pages) that sets attributes when a new Book is created.
  • Circle class with a default constructor setting radius to 1 and parameterised constructor accepting a radius value.
  • Employee class where constructor validates that salary is non-negative and raises an error otherwise.
📊 Visual ideas
Sequence showing creation: call constructor → allocate memory → set attributes → return object reference.
💻5

Access Specifiers: public, private and protected

Purpose of access specifiers
Access specifiers control which parts of a program can see or use class members (attributes and methods). They are the language mechanism used to enforce encapsulation and limit coupling between classes. Correct use of these specifiers leads to safer and more maintainable code.

Public members
Public members (+) are visible to all code that has access to the class. Public methods form the class's interface; external code relies on these to interact with objects. Keep the public interface small and focused, exposing only the operations that clients truly need.

Private members
Private members (-) are accessible only inside the class itself. Attributes are commonly private so that only class methods can change them, ensuring that invariants and validation checks are enforced. Private methods are used for internal helper functions that should not be visible to or called by outside code.

Protected members
Protected members (#) are visible within the class and to subclasses (derived classes). Protected members allow subclasses to access or extend internal behaviour while still hiding those details from other classes. Use protected sparingly: exposing too much to subclasses can create tight coupling between parent and child implementations.

Package or internal visibility
Some languages provide additional levels like package or internal visibility that restrict access to a set of classes within the same module or package. These provide a balance between full privacy and public visibility for closely related classes within a component.

Design guidelines
1) Prefer private for attributes. 2) Expose behaviour through public methods rather than giving direct access to data. 3) Use protected only when subclasses truly require access. 4) Minimise the public surface area to allow future internal changes without breaking client code.

Example trade-offs
Making a field public may seem easier, but it ties external code to that internal representation; changing it later will break clients. Controlled access via methods gives flexibility to change internal structure while keeping the same external behaviour.

📌 Examples
  • Person class with private attribute age and public methods setAge(value) and getAge() to validate and access age.
  • Base class Vehicle with protected attribute enginePower so subclass Car can access it for specialised behaviour.
  • Library class offering public checkout(book) while keeping internal inventory map private.
📊 Visual ideas
Venn-like diagram showing private circle inside class, protected extending to subclasses, public reaching all external code.
💻6

Inheritance: Reuse and Specialisation

What inheritance gives you
Inheritance allows a class (subclass) to derive from another class (superclass), gaining its attributes and methods. This supports reuse of common behaviour and lets you express specialisation: the subclass is a more specific version of the superclass. For example, if Vehicle defines move() and speed, Car and Bike can inherit those features and add their own specifics.

How it reduces duplication
Without inheritance, shared code must be duplicated across classes, making maintenance harder. With inheritance, common code resides in the parent class and is inherited by children. Fixes or improvements in the parent automatically apply to subclasses, reducing chances of inconsistent behaviour. Careful design ensures the parent contains only behaviour that truly belongs to all its children.

Extending and overriding
Subclasses can add new attributes and methods or override parent methods to change behaviour. Overriding lets a subclass provide a specialised implementation while preserving the parent’s interface. Often a subclass calls the parent implementation and then extends it, rather than fully replacing it. When overriding, maintain preconditions and postconditions so that substitutability remains valid.

Multiple inheritance and alternatives
Some languages allow multiple inheritance where a class derives from several parents. This can lead to complexity such as the diamond problem where a method appears in multiple parent paths. To avoid such complexities, many languages provide interfaces or traits that supply type-based capabilities without concrete implementation inheritance. Use interfaces for behaviour contracts and single inheritance for concrete reuse.

Design principles and Liskov Substitution
Use inheritance to model true "is-a" relationships: a Car is a Vehicle, a Square is a Shape. The Liskov Substitution Principle (LSP) guides correct use: objects of a subclass must be usable wherever the parent type is expected without surprising behaviour. Violating LSP leads to bugs when code written for the parent type encounters unexpected subclass behaviour.

When not to use inheritance
Do not use inheritance merely for code reuse if there is no conceptual parent-child relationship. Prefer composition in cases where one object contains or uses another but is not a specialised form of it. Composition keeps classes loosely coupled and easier to change. Also prefer shallow hierarchies to deep ones to simplify understanding and maintenance.

Practical tips
Document the responsibilities of base classes clearly. Design base classes with stable contracts and avoid exposing too many protected members that tie subclasses to internal representations. When in doubt, start with composition and refactor to inheritance only if a true specialization relationship emerges.

📌 Examples
  • Class Animal with method makeSound(); subclass Dog overrides makeSound() to bark while Cat overrides to meow.
  • Class Shape with method area(); subclasses Rectangle and Circle implement area() differently.
  • Class Employee as parent and Manager as subclass with additional attribute teamSize and method manageTeam().
📊 Visual ideas
A simple tree showing parent class at top (Vehicle) and child classes below (Car, Bike) with arrows pointing downward.
💻7

Polymorphism: Same Interface, Different Implementations

Core idea of polymorphism
Polymorphism allows code to treat objects of different classes in a uniform way through a common interface. The exact method executed depends on the object's runtime type. This enables flexible and extensible programmes that require little or no change when new classes are added which follow the same interface.

Kinds of polymorphism
Two commonly discussed kinds are compile-time polymorphism and runtime polymorphism. Compile-time polymorphism includes method overloading where multiple methods share a name but differ in parameter lists. Runtime polymorphism occurs when a subclass overrides a method of its parent and a parent-type reference points to a subclass object; the runtime selects the subclass method.

Designing for polymorphism
Program to interfaces or abstract base classes rather than concrete classes. For instance, write functions that accept a parameter of type Shape rather than Circle. Any class implementing Shape can then be passed to the function, and the correct method implementations run. This reduces conditional checks and supports the Open/Closed Principle: you can add new classes without changing existing code.

Practical patterns
Interfaces and abstract classes are common tools for polymorphism. Use an interface to define a capability like Comparable or Drawable. Concrete classes implement those methods in their own way. Polymorphism is also the basis for many design patterns such as Strategy, where behavior is selected at runtime by choosing a particular implementation of an interface.

Risks and contracts
When overriding methods, ensure the subclass respects the expected contract of the parent method: do not strengthen preconditions or weaken postconditions. Unexpected changes in behaviour can break client code that relies on parent semantics. Document intended behaviour and test subclass instances in contexts where parent types are used.

Examples and benefits
Example: a function drawAll(listOfShapes) calls draw() on each Shape. Circle, Rectangle and Triangle implement draw() differently but the same code draws all. Benefits include simpler code, easier extension and reduction of conditional type checks. Polymorphism helps build systems that are modular, extendable and easier to maintain.

📌 Examples
  • Interface Drawable with method draw(); classes Circle and Square implement draw() to render different shapes.
  • Function processPayment(paymentMethod) where paymentMethod could be CardPayment or UPI and each implements pay(amount) differently.
  • Overloaded add(a,b) methods for integers and floats showing compile-time polymorphism.
📊 Visual ideas
Diagram illustrating a reference of type Shape pointing to different subclass objects and invoking draw().
💻8

Object Relationships: Association, Aggregation and Composition

Why relationships matter
Classes rarely live alone: they interact. Modelling how objects relate clarifies responsibility, lifetime and ownership. Three commonly used relationship types are association, aggregation and composition. They help decide which class should create or destroy objects and how tightly they are coupled.

Association — loose link
Association is a simple link where objects know about each other and can call methods, but neither owns the other’s lifecycle. For example, a Teacher may be associated with many Students; both can exist independently. Association is used for collaborations where objects use each other but do not manage each other’s existence.

Aggregation — whole-part but independent
Aggregation is a form of association indicating a whole-part relationship where parts can exist independently of the whole. For instance, a Department may aggregate Professors; a Professor can move to another Department and outlive a particular Department. Aggregation shows a weaker ownership and suggests parts are shared or reusable across different wholes.

Composition — strong ownership
Composition expresses strong ownership: parts belong to a whole and cannot meaningfully exist outside it. If the whole is destroyed, so are the parts. Example: a House composed of Room objects; rooms are part of that house model and typically are not independent entities in the system. Composition often implies that the whole creates and destroys the parts.

Modelling consequences
Choosing composition versus aggregation affects memory and lifecycle management. Composition usually means the parent constructs and manages child objects, while aggregation suggests external code may provide parts. Carefully assess whether a part makes sense independently before modelling it as composite.

UML and multiplicity
In UML, association is a plain line, aggregation an open diamond and composition a filled diamond at the whole end. Multiplicity indicators (1, 0..*, *) show how many instances participate. Clear multiplicity helps avoid ambiguous designs and clarifies expected usage patterns.

📌 Examples
  • Association: Customer and Bank interacting for transactions but both exist independently.
  • Aggregation: Team has Players; players can be part of other teams or exist without a team.
  • Composition: Book and its Pages where pages are created as part of a Book and do not exist separately.
📊 Visual ideas
Three small UML sketches: plain line for association, open diamond for aggregation, filled diamond for composition with multiplicity labels.
💻9

Message Passing and Method Invocation

Objects communicate by messages
In object-oriented systems, interaction between objects is performed by sending messages. A message generally corresponds to invoking a method on the target object, optionally passing parameters and receiving a result. This message-based communication keeps components decoupled: callers depend on the receiver's interface rather than its internal details.

Method call mechanics
When a method is invoked, the runtime locates the method implementation in the target object's class (considering inheritance and overriding), binds parameters, executes code in the method body and returns control to the caller with any return value. Dynamic dispatch ensures the most specific implementation is chosen at runtime for overridden methods. The call stack records active method calls so control can return correctly after each return.

Parameter passing and side-effects
Languages vary in how they pass parameters. Primitive values are often passed by value, meaning the method works on a copy. Object references are usually passed so the method can change the referred object's state. Understanding whether a method mutates its arguments or works with copies is important to avoid unintended side-effects. Document whether a method mutates its inputs or returns new objects.

Synchronous versus asynchronous invocation
Most calls are synchronous: the caller waits until the called method finishes. In concurrent or distributed systems, asynchronous message passing lets the caller continue while the recipient processes the message later. Asynchronous patterns require callbacks, listeners, futures or promises to obtain results eventually and need careful error handling and concurrency control.

Respecting encapsulation through messages
Message passing supports encapsulation because objects expose behaviour (methods) rather than internal state. Callers request actions via messages and do not rely on representation details. Design small, well-named methods that clearly express intent, which makes message-based interactions easier to understand and use.

Error handling and contracts
Define method contracts: preconditions the caller must satisfy, and postconditions the method guarantees. Methods can signal errors via return values, exceptions or status objects. Clear contracts and consistent error signalling make integration between objects safer and simplify debugging when message exchanges fail.

📌 Examples
  • Object A calls account.deposit(500) on a BankAccount object B — a message instructing B to add 500 to its balance.
  • A GUI Button sends a click event message to a Window object which handles the event by invoking appropriate methods.
  • A Logger object receives log(message) calls from many objects and writes entries to a file; callers do not need to know how logging is implemented.
📊 Visual ideas
Sequence diagram sketch showing Object1 -> Object2: method(params) and Object2 -> Object1: return value.
💻10

Static Members and Class-level Behaviour

Static members explained
Static (or class) members belong to the class itself rather than to individual instances. A static attribute is shared across all instances and is stored once at the class level. A static method can be called without creating any object and typically performs operations that do not depend on instance-specific data.

When to use static attributes
Use static attributes for values that are common to all instances, such as configuration constants or counters tracking the total number of created objects. For example, a class may maintain a static totalCount that increments in each constructor to know how many instances exist or were created. This shared state is convenient but must be used carefully because changes affect every instance.

When to use static methods
Static methods are useful for utility operations (for example, Math.max()) and factory methods that create and return instances. A factory method can centralise complex creation logic so callers do not need to know the details of constructing different concrete classes.

Thread-safety and concurrency
Because static attributes are shared, concurrent access can lead to race conditions if multiple threads read and write them. Synchronisation mechanisms (locks, atomic operations) may be required to make updates safe. Avoid using mutable static state when possible in multi-threaded contexts to reduce complexity and bugs.

Testing and global state
Static mutable state makes testing harder because tests can interfere with each other by changing shared values. Prefer passing dependencies explicitly or using dependency injection to make testing easier. If static values are necessary, provide ways to reset or configure them during tests.

Design advice
Use static members for logically shared data or stateless helper functions. Avoid static state that creates hidden coupling between classes. Keep static usage minimal and document why a member is static to help future maintainers.

📌 Examples
  • Class Counter with static attribute totalCount incremented in every constructor to track number of instances.
  • MathUtils class with static method max(a,b) that returns the larger value without creating an object.
  • Configuration class with static constant DEFAULT_TIMEOUT used across the application.
📊 Visual ideas
Diagram showing class box with a static section separated and arrow pointing to shared memory for static members.
💻11

Abstract Classes and Interfaces

Abstract classes
An abstract class defines a base type that may provide some implemented methods and may declare abstract methods that do not have implementations. Abstract classes cannot be instantiated directly; they are intended to be subclassed by concrete classes that implement the abstract methods. Abstract classes are useful when several related classes share common code but also need to supply specialized behaviour.

Interfaces
An interface is a pure contract listing method signatures (and sometimes constants) that implementing classes must provide. Interfaces do not contain implementation (or contain limited default implementations in some languages). They describe capabilities rather than implementation and allow unrelated classes to be treated uniformly if they implement the same interface.

Choosing between them
Use an abstract class when you want to share code among related classes and enforce a common base. Use an interface when you want to define a role or capability that many different classes might provide without implying inheritance. Interfaces enable multiple-type polymorphism: a class can implement several interfaces to express many capabilities.

Polymorphism and substitution
Both abstract classes and interfaces support polymorphism: code can refer to the abstract type and work with any concrete implementation. This simplifies code and supports extension: new concrete classes implementing the interface or extending the abstract class integrate easily with existing code.

Design trade-offs
Abstract classes allow code reuse but create tighter coupling via inheritance. Interfaces keep types loosely coupled but may require duplication of helper code unless helper classes or default methods are provided. Consider maintainability and future extension when choosing between them.

Practical uses
Interfaces commonly describe behaviours like Comparable (objects that can be ordered) or Runnable (objects that can run on a thread). Abstract classes are used when there is a meaningful base implementation, such as a BaseController providing common request handling with abstract methods for module-specific details.

📌 Examples
  • Interface Flyable with method fly(); classes Bird and Airplane implement Flyable differently.
  • Abstract class Employee with implemented method calculateBonus() and abstract method workDetails() that subclasses must define.
  • Comparable interface used to enable sorting of objects by providing compareTo() method.
📊 Visual ideas
Diagram showing interface box with methods and arrows from multiple classes implementing the interface.
💻12

UML Class Diagrams: Notation and Interpretation

Why use UML class diagrams
UML class diagrams are a standard visual language to show classes, their members and relationships. They help designers and programmers communicate structure before or during implementation. A clear diagram makes it easier to understand responsibilities, object interactions and dependencies at a glance.

Class box structure
A class is drawn as a rectangle divided into three compartments: top for the class name, middle for attributes and bottom for methods. Visibility symbols precede names: '+' for public, '-' for private and '#' for protected. Including types and return types helps readers know what data each member holds or returns.

Attributes and methods details
Attributes are listed with name and type and can include default values or multiplicities when needed. Methods show name, parameters and return type. Explicitly specifying types makes the diagram clearer and aids implementation. For example: - balance: float = 0.0 and + deposit(amount: float): void.

Relationships and symbols
Association is shown as a plain line connecting classes. Aggregation uses an open diamond at the whole end to show a weak whole-part relationship. Composition uses a filled diamond to denote strong ownership where parts are created and destroyed with the whole. Inheritance is shown with a solid line and a hollow arrow pointing to the parent class.

Multiplicity and navigability
Multiplicity near the ends indicates how many instances participate in a relationship, such as 1, 0..*, or *. Navigability arrows show which class knows about or can access the other. Properly labelling multiplicities and navigability avoids misinterpretation of how objects relate at runtime.

Reading and refining diagrams
Begin with high-level diagrams showing main classes and their relations. Then refine by adding important attributes, methods and multiplicities. Use sequence diagrams to show typical interactions for key use cases. Keep diagrams concise; too much detail can hide the overall structure. Update diagrams as design evolves so they remain useful documentation.

📌 Examples
  • Draw a UML class for Student with attributes -rollNo:int, -name:String and methods +getDetails():String.
  • Diagram showing Course class composed of multiple Module objects with filled diamond and multiplicity 1..*.
  • A simple inheritance diagram with Animal as parent and Dog, Cat as subclasses using hollow arrowheads.
📊 Visual ideas
A standard UML class box divided into three compartments and small sketches for association, aggregation, composition and inheritance symbols.
💻13

Object Lifecycle and Memory Management

Stages of an object's life
Objects typically pass through creation, initialisation, use and destruction. Creation allocates memory and resources, the constructor initialises state, methods are called while the object is in use, and finally the object becomes unused and may be destroyed or garbage-collected. Understanding these stages helps manage resources and avoid leaks.

Memory allocation and references
When an object is created, memory is allocated to store its attributes. Variables hold references (or pointers) to objects. The number and visibility of references determine whether an object is considered reachable. Reachable objects cannot be reclaimed until references are removed or go out of scope.

Garbage collection vs manual deallocation
Managed languages provide garbage collection that frees memory of objects that are no longer reachable. In languages without garbage collection, programmers must explicitly free memory to avoid memory leaks. Even in managed environments, non-memory resources like files, sockets and database connections must be released explicitly because garbage collection does not guarantee timely cleanup.

Reference counting and cycle issues
Reference counting deallocates objects when their reference counts reach zero, but cycles of references can prevent deallocation unless broken explicitly. Other garbage collection techniques use reachability analysis to find objects unreachable from root references. Each approach has trade-offs in performance and predictability.

Finalisers and explicit cleanup
Finaliser or destructor methods may run when an object is collected, but their timing is often unpredictable. It is better to provide explicit close or dispose methods (and use language constructs like try-finally or try-with-resources) to ensure timely release of critical resources. This makes resource management deterministic and reduces runtime errors in long-running applications.

Practical suggestions
Avoid holding unnecessary references that prolong object lifetime. Use weak references for caches to allow garbage collection. Keep object scope narrow and free external resources promptly. Monitor memory usage and test for leaks, particularly in long-running services.

📌 Examples
  • Creating many short-lived temporary objects in a loop increases memory pressure compared to reusing a single mutable object.
  • Using try-with-resources or finally blocks to ensure files are closed even if an exception occurs (explicit resource cleanup).
  • A cache holding strong references may prevent cached objects from being garbage-collected; using weak references avoids that problem.
📊 Visual ideas
Flow showing creation → initialisation → usage → eligible for garbage collection → destruction with note about roots and reachability.
⚖️14

Design Principles: Single Responsibility and Separation of Concerns

Single Responsibility Principle (SRP)
SRP states that a class should have only one reason to change. This means a class should focus on a single responsibility or purpose. When a class mixes unrelated responsibilities—such as handling user input, business rules and file storage—it becomes hard to test and maintain because changes in one area affect the others. Designing classes with one clear responsibility reduces coupling and localises the impact of changes.

Separation of Concerns
Separation of concerns divides a programme into distinct sections that each address a different concern. Typical layers include presentation (UI), business logic (services), and data access (repositories). Each layer should interact with others through well-defined interfaces. This separation improves clarity, enables parallel development, and simplifies testing because components can be tested independently or with mocks.

Benefits of applying these principles
Following SRP and separation of concerns improves cohesion, which means related functionality is grouped together, and reduces coupling between unrelated parts. Such designs are easier to modify, extend, and understand. Smaller classes with focused responsibilities are often simpler to write unit tests for and result in faster, safer refactoring.

How to refactor towards SRP
Identify a class that performs multiple tasks and ask which parts are conceptually different. Extract responsibilities into new classes with clear names. For example, an OrderProcessor handling input validation, payment and persistence can be split into OrderValidator, PaymentProcessor and OrderRepository. Move code that deals with external systems into separate adapters so domain logic remains pure and testable.

Use interfaces and dependency injection
Define interfaces to decouple components. Dependency injection supplies implementations to classes at runtime, which makes swapping or mocking components easy for tests. For instance, the business layer can depend on an IOrderRepository interface instead of a concrete database implementation, enabling use of in-memory repositories for testing.

Balance and practical considerations
Avoid over-splitting into too many tiny classes which can increase navigation cost and reduce clarity. Aim for a pragmatic balance: classes should be small enough to be focused but large enough to represent meaningful concepts. Keep design simple initially and refactor to improve SRP as requirements evolve.

📌 Examples
  • Refactor a Monolithic OrderProcessor class into OrderValidator, PaymentProcessor and OrderRepository classes each with a single responsibility.
  • Separate UI code from data access code so changes to the database layer do not affect the user interface.
📊 Visual ideas
Layered diagram showing presentation layer, service layer and data layer separated with clear interfaces between them.
🔶15

Design Patterns (Introductory) and Object-Oriented Analysis

Why learn patterns and analysis
Design patterns are commonly occurring solutions to recurring problems in software design. Object-oriented analysis helps convert requirements into classes and objects. Together they give a practical toolkit: analysis finds the right objects and relationships; patterns suggest proven ways to organise interactions between those objects.

Object-oriented analysis (OOA) steps
1) Read requirements and identify actors and use-cases. 2) Find candidate classes by spotting important nouns in descriptions (Customer, Order, Product). 3) For each candidate class, determine attributes and key methods. 4) Establish relationships: which classes use, contain or inherit from others? 5) Create UML diagrams (class and sequence) to visualise structure and interactions, then refine iteratively.

Factory pattern (creational)
The Factory pattern provides a method (factory) to create objects instead of calling constructors directly. This centralises creation logic and allows returning different concrete subclasses based on input or configuration. Use it when object creation is complex, requires configuration, or the exact class to instantiate may vary at runtime.

Observer pattern (behavioural)
The Observer pattern defines a one-to-many relationship: when one object (subject) changes state, a set of observers are notified automatically. This suits event-driven designs like GUIs or model-view updates. Observers register themselves with the subject and receive update notifications when relevant changes occur.

Applying patterns during analysis
During analysis, recognise situations where patterns help: if creation is conditional or configurable, introduce a factory; if many parts must react to changes in a single object, design subject-observer relationships. Use UML to depict pattern participants: factory classes, product interfaces and observer lists with update messages.

Practical trade-offs
Patterns add indirection and may complicate small programmes; use them when they solve real design problems or improve extensibility. Keep designs simple at first and refactor to patterns when the need becomes clear. Document chosen patterns to help future maintainers understand design intent.

📌 Examples
  • Factory: DocumentFactory.create(type) returns PdfDocument or WordDocument based on the given type string, hiding construction details from callers.
  • Observer: A WeatherStation subject notifies display widgets (temperature, humidity) which implement update() to refresh display when data changes.
  • OOA example: From library requirements, identify classes Book, Member, Loan and design Loan as an association between Book and Member with appropriate methods.
📊 Visual ideas
Sequence showing Factory creating different concrete objects; diagram showing Subject with arrows to multiple Observers; use-case to class mapping sketch.

Key Concepts

Object
A concrete instance of a class that holds state (attributes) and behaviour (methods).
Class
A blueprint that defines the structure (attributes) and behaviour (methods) for its objects.
Attribute
A named piece of data stored within an object representing its state.
Method
A function defined in a class that describes an object's behaviour.
Encapsulation
The practice of bundling data and methods and restricting direct access to internal state.
Inheritance
A mechanism where a class derives from another to reuse and extend its features.
Polymorphism
The ability to use the same interface to operate on objects of different types.
Constructor
A special method that initialises a new object when it is created.
Destructor
A method or mechanism that cleans up resources when an object is destroyed.
Association
A general relationship between two classes where objects interact but have independent lifecycles.
Aggregation
A whole-part relationship where parts can exist independently of the whole.
Composition
A strong whole-part relationship where parts cannot exist separate from the whole.
Interface
A specification that defines a set of methods a class must implement.
Abstract class
A class that may contain abstract methods and cannot be instantiated directly.
Static member
A class-level attribute or method shared by all instances rather than belonging to any one object.
UML
Unified Modelling Language, a standard way to visualise system design with diagrams.
Liskov Substitution Principle
A design principle stating subclasses should be usable wherever their parent class is expected.
Factory pattern
A creational pattern that centralises object creation in a factory instead of calling constructors directly.
Observer pattern
A behavioural pattern where a subject notifies multiple observers when its state changes.

Practice Questions

  1. What is a class and what is an object? Give one example. / एक क्लास क्या है और एक ऑब्जेक्ट क्या है? एक उदाहरण दीजिए।
    Show answer

    A class is a blueprint defining attributes and methods; an object is an instance of that class with specific values. Example: Class Book with attributes title and author; a Book object could be title='Hamlet', author='Shakespeare'. / एक क्लास वह खाका है जो गुण (attributes) और विधियाँ (methods) परिभाषित करती है; एक ऑब्जेक्ट उस क्लास का एक उदाहरण है जिसमें विशेष मान होते हैं। उदाहरण: Book क्लास जिसमें attributes title और author हों; एक Book ऑब्जेक्ट हो सकता है title='Hamlet', author='Shakespeare'.

  2. Describe encapsulation and explain why it is important. / एन्कैप्सुलेशन का वर्णन कीजिए और यह क्यों महत्वपूर्ण है बताइए।
    Show answer

    Encapsulation bundles data and methods together and restricts direct access to internal state, typically using private attributes and public methods. It is important because it protects object integrity, enforces validation, reduces coupling and makes code easier to maintain. / एन्कैप्सुलेशन डेटा और विधियों को एक साथ बाँध देता है और आंतरिक स्थिति तक सीधे पहुँच को सीमित करता है, सामान्यतः private attributes और public methods के उपयोग से। यह महत्वपूर्ण है क्योंकि यह ऑब्जेक्ट की अखंडता की रक्षा करता है, मान्यकरण लागू करता है, कपलिंग कम करता है और कोड को बनाए रखना आसान बनाता है।

  3. What is the difference between aggregation and composition with suitable examples. / Aggregation और Composition में क्या अंतर है? उपयुक्त उदाहरण दीजिए।
    Show answer

    Aggregation is a whole-part relationship where the part can exist independently of the whole (e.g., Department aggregates Professor; a Professor can exist without the Department). Composition is a stronger relationship where the part cannot exist without the whole (e.g., Book composed of Page objects; pages are not meaningful outside that Book). / Aggregation एक whole-part संबंध है जहाँ part पूरे से स्वतंत्र रूप से मौजूद रह सकता है (उदा., Department में Professors होते हैं; Professor Department के बिना भी मौजूद हो सकता है)। Composition अधिक मजबूत है जहाँ part पूरे के बिना अस्तित्व नहीं रखता (उदा., Book में Pages होते हैं; वे उस Book के बिना निरर्थक होते हैं)।

  4. Explain polymorphism with an example in which two classes provide different implementations for the same method. / Polymorphism समझाइए और एक उदाहरण दीजिए जिसमें दो क्लासें एक ही विधि के लिए अलग- अलग कार्यान्वयन दें।
    Show answer

    Polymorphism allows using the same method name for different classes where the actual method executed depends on the object's type at runtime. Example: Class Animal has method makeSound(); Dog implements makeSound() as 'bark' and Cat implements makeSound() as 'meow'. A function call animal.makeSound() will produce different sounds depending on whether animal refers to a Dog or a Cat. / Polymorphism एक ही विधि नाम को अलग-अलग क्लासों में उपयोग करने देता है जहाँ वास्तविक क्रिया रनटाइम पर ऑब्जेक्ट के प्रकार पर निर्भर करती है। उदाहरण: Class Animal में method makeSound(); Dog में makeSound() 'bark' और Cat में 'meow' करता है। कॉल animal.makeSound() अलग-अलग परिणाम देगा यह निर्भर करता है कि animal Dog है या Cat।

  5. Draw and label a simple UML class box for a Student with rollNo:int and name:String and method getDetails():String. / Student के लिए एक सरल UML क्लास बॉक्स बनाइए जिसमें rollNo:int, name:String और method getDetails():String हो और उसे लेबल कीजिए।
    Show answer

    A UML class box has three compartments. Top: Student. Middle: - rollNo: int\n- name: String. Bottom: + getDetails(): String. The '-' indicates private attributes and '+' indicates public method. / UML क्लास बॉक्स में तीन खंड होते हैं। ऊपर: Student। मध्य: - rollNo: int\n- name: String। नीचे: + getDetails(): String। '-' private attributes दर्शाता है और '+' public method दर्शाता है।

  6. What is a constructor? How does it differ from an ordinary method? / Constructor क्या होता है? यह सामान्य विधि से कैसे भिन्न होता है?
    Show answer

    A constructor is a special method called when an object is created to initialise the object's state. It usually has the same name as the class and does not return a value. An ordinary method is invoked on an existing object, may return a value, and can have any name. / Constructor एक विशेष विधि है जो ऑब्जेक्ट के निर्माण पर उसे आरम्भ करने के लिए कॉल होती है। यह सामान्यतः क्लास के नाम के समान होता है और कोई मान वापस नहीं करता। सामान्य विधि किसी मौजूदा ऑब्जेक्ट पर चलती है, मान वापस कर सकती है और किसी भी नाम की हो सकती है।

  7. Give two reasons to prefer composition over inheritance. / Inheritance की तुलना में composition को प्राथमिकता देने के दो कारण बताइए।
    Show answer

    1) Composition offers better flexibility: parts can be changed at runtime and classes remain loosely coupled. 2) Composition avoids inappropriate 'is-a' relationships and reduces the risk of fragile hierarchies when classes evolve. / 1) Composition अधिक लचीलापन देता है: parts को रनटाइम पर बदला जा सकता है और क्लासें ढीली तौर पर जुड़ी रहती हैं। 2) Composition अनुचित 'is-a' संबंधों से बचाता है और क्लास विकास के दौरान कमजोर हायार्की के जोखिम को कम करता है।

  8. Explain how static members are different from instance members. Give one use for a static member. / Static सदस्य और instance सदस्य में क्या अंतर है? Static सदस्य के एक उपयोग का उदाहरण दीजिए।
    Show answer

    Static members belong to the class itself and are shared by all instances; instance members belong to each object separately. One use of a static member is to keep a counter of how many objects of a class have been created (a shared totalCount attribute). / Static सदस्य क्लास के साथ जुड़े होते हैं और सभी instances के बीच साझा होते हैं; instance सदस्य प्रत्येक ऑब्जेक्ट के साथ अलग होते हैं। Static सदस्य का एक उपयोग यह है कि यह ट्रैक करने के लिए उपयोग किया जा सकता है कि किसी क्लास के कितने ऑब्जेक्ट बनाए गए हैं (साझा totalCount attribute)।

  9. What is the Liskov Substitution Principle and why is it important? / Liskov Substitution Principle क्या है और यह क्यों महत्वपूर्ण है?
    Show answer

    The Liskov Substitution Principle states that objects of a subclass should be replaceable for objects of the parent class without altering correctness. It is important because it ensures reliable polymorphism and prevents unexpected behaviour when using base class references to hold subclass objects. / Liskov Substitution Principle कहता है कि सबक्लास के ऑब्जेक्ट्स को पैरेंट क्लास के ऑब्जेक्ट्स की जगह बिना व्यवहार बिगाड़े उपयोग किया जा सके। यह महत्वपूर्ण है क्योंकि यह भरोसेमंद polymorphism सुनिश्चित करता है और बेस क्लास संदर्भों में सबक्लास ऑब्जेक्ट्स के उपयोग से अप्रत्याशित व्यवहार को रोकता है।

  10. Write short notes on garbage collection and why explicit resource release might still be necessary. / Garbage collection पर संक्षेप में लिखिए और बताइए कि क्यों स्पष्ट संसाधन विमोचन अभी भी आवश्यक हो सकता है।
    Show answer

    Garbage collection automatically frees memory of objects that are no longer reachable, relieving the programmer from manual memory deallocation. However, explicit resource release is still necessary for non-memory resources (files, sockets, database connections) because garbage collection is non-deterministic and may not run immediately; relying on it can lead to resource exhaustion. Therefore explicit close/dispose methods or language constructs (like try-with-resources) should be used. / Garbage collection स्वयं उन ऑब्जेक्ट्स की मेमोरी मुक्त कर देता है जो अब पहुँच योग्य नहीं हैं, जिससे प्रोग्रामर को मैन्युअल मेमोरी मुक्त करने की आवश्यकता कम हो जाती है। फिर भी, स्पष्ट संसाधन विमोचन गैर-मेमोरी संसाधनों (फाइल, सॉकेट, DB कनेक्शन) के लिए आवश्यक है क्योंकि garbage collection समय नहीं बताता और तुरंत नहीं चल सकता; इस पर निर्भर करने से संसाधन समाप्त हो सकते हैं। इसलिए explicit close/dispose विधियाँ या try-with-resources जैसे भाषा निर्माण उपयोग किए जाने चाहिए।

Related Laws & Principles

Explore all

Foundational laws & principles connected to this chapter — tap to open in the Laws Explorer.

Loading related laws…
Sourced from 0 content files · LLOS Learn · browse all chapters