Lesson 1
Why use Object-Oriented Programming?
Object orientation has become the development paradigm of choice for programmers in the 1990s, 2000s, and beyond.
In this module, you will explore how object-oriented programming (OOP) differs from traditional, procedural, or structured programming and how you can exploit those differences to produce faster, more maintainable code. In this module, you will learn:
- How traditional programs are designed
- How object-oriented programs are designed
- How to choose the initial classes in your system
- Some of the qualities of a "good class" for an object-oriented application
Object-oriented programming (OOP) is a programming paradigm that uses
objects to design applications and computer programs. It uses several techniques from previously established paradigms, including encapsulation, inheritance, and polymorphism.
Even though it originated in the 1960s, OOP was not commonly used in mainstream software application development until the 1990s.
Today, many popular programming languages support OOP. The origins of object-oriented programming reach all the way back to the 1960s, when the field of software engineering had begun to discuss the idea of a software crisis.
As hardware and software became increasingly complex, how could software quality be maintained?
Object-oriented programming addresses this problem by strongly emphasizing
modularity in software.
What is Object Oriented Programming?
Object oriented programming is a programming paradigm where concepts in the program are represented by objects. Each object is an instance of a class, which can be seen as a blueprint or template of the characteristics of the object . Contrary to procedural programming, these characteristics include data, attributes or variables describing the object's state and behavior. The methods or procedures describe the actions an object can perform.
In C++, Object-Oriented Programming (OOP) is primarily composed of the following constructs:
- Classes: A class is a blueprint for creating objects (instances). It encapsulates data for the object (attributes) and methods (functions) that operate on the data.
- Objects: Objects are instances of classes. They represent real-world entities with both state (attributes) and behavior (methods).
- Encapsulation: This refers to bundling the data (attributes) and the methods that manipulate the data into a single unit, the class. It also includes restricting access to certain components (using access specifiers like `private`, `protected`, and `public`).
- Inheritance: Inheritance allows a class (derived class) to inherit attributes and methods from another class (base class). This promotes code reuse and establishes a natural hierarchy between classes.
- Polymorphism: Polymorphism allows objects to be treated as instances of their parent class, even though each object may exhibit different behavior. It’s achieved through function overloading, operator overloading, and, most importantly, through virtual functions for runtime polymorphism.
- Abstraction: Abstraction involves hiding the complex implementation details and showing only the essential features of an object. In C++, this is often achieved using abstract classes (classes with at least one pure virtual function) and interfaces.
These constructs work together to enable the design and development of flexible, modular, and reusable code using OOP principles in C++.
Object-Oriented Analysis
Choosing between Imperative Programming and Object-Oriented Programming
Choosing between imperative programming and Object-Oriented Programming (OOP) depends on the nature of the problem you're trying to solve, the specific requirements of the project, and the programming environment. Here's a breakdown of when you might prefer imperative programming over OOP:
When to Use Imperative Programming
- Simple, Small-Scale Programs: Imperative programming is often better suited for small, straightforward programs where the complexity of creating classes and objects might be unnecessary. If your task is simple, such as a script that processes data or automates a routine task, imperative programming can be more direct and easier to implement.
- Performance-Critical Code: In certain performance-critical applications, imperative programming can offer more fine-grained control over memory usage and processing. Since imperative code is typically more explicit in its control flow and state changes, it can sometimes be optimized more easily for speed and memory efficiency than OOP code.
- Procedural Tasks: When your program is focused on a series of steps or instructions to manipulate data, imperative programming can be a natural fit. For instance, algorithmic or procedural tasks, like manipulating arrays or performing calculations, might be more straightforward to express imperatively.
- Low-Level Programming: For low-level programming tasks, such as system programming, embedded programming, or writing drivers, imperative programming is often preferred. This is because you typically need direct control over hardware and memory, which imperative programming provides.
- Scripting and Automation: For tasks involving scripting or automation, such as writing shell scripts, batch files, or simple Python scripts, imperative programming can be more appropriate. These tasks usually require executing a sequence of commands or operations, which aligns well with the imperative paradigm.
- Functional or Reactive Programming Integration: In some cases, you might be working within a functional or reactive programming paradigm, where imperative programming is used in specific parts of the codebase. Here, the focus is on functions or data flow rather than objects and classes, and imperative code can be employed to manage side effects or state changes.
Examples:
- Data Processing Scripts: A simple script that reads a file, processes the data, and writes the output might be written imperatively for clarity and simplicity.
- Algorithm Implementation: Implementing a sorting algorithm or a search routine might be done imperatively, focusing on the specific steps needed to achieve the desired result.
- System Utilities: Writing utilities for managing system resources (like memory management or file handling) often requires an imperative approach for direct control and efficiency.
Comparison with Object-Oriented Programming (OOP):
OOP is typically better suited for:
- Complex, Large-Scale Systems: Where structuring the code into objects and classes helps manage complexity.
- Systems with Inheritance or Polymorphism: Where behavior and state are naturally organized into hierarchies.
- Maintainability: Where code reusability and separation of concerns are important.
Summary:
Use imperative programming when your task is simple, performance-critical, or low-level, or when you're writing scripts or procedural code. It provides direct and explicit control over the execution flow, making it ideal for tasks that don't require the additional abstraction and structure provided by Object-Oriented Programming (OOP).
What is Functional Programming
Programming in a functional language consists of building definitions and using the computer to evaluate expressions.
The primary role of the programmer is to construct a function to solve a given problem. This function, which may involve a number of subsidiary functions, is expressed in notation that obeys normal mathematical principles.
The primary role of the computer is to act as a calculator: its job is to evaluate expressions and print the results. In this respect, the computer acts much like an ordinary pocket calculator. What distinguishes a functional calculator from a standard calculator is the programmer's ability to make definitions to increase its powers of calculation.
Expressions which contain occurrences of the names of functions defined by the programmer are evaluated by using the given definitions as simplification (or 'reduction') rules for converting expressions to printable form.
A characteristic feature of functional programming is that if an expression possesses a well-defined value, then the order in which a c.omputer may carry out the evaluation does not affect the outcome. In other words, the meaning of an expression is its value and the task of the computer is simply to obtain it. It follows that expressions in a functional language can be constructed,
manipulated and reasoned about, like any other kind of mathematical expression, using more or less familiar algebraic laws. The result, as we hope to justify, is a conceptual framework for programming which is at once very
simple, very concise, very flexible and very powerful.