148 lines
3.8 KiB
Markdown
148 lines
3.8 KiB
Markdown
# CSE332S Lecture 17
|
||
|
||
## Object Oriented Programming Building Blocks
|
||
|
||
OOP Building Blocks for Extensible, Flexible, and Reusable Code
|
||
|
||
Today: Techniques Commonly Used in Design Patterns
|
||
|
||
- **Program to an interface** (last time)
|
||
- **Object composition and request forwarding** (today)
|
||
- Composition vs. inheritance
|
||
- **Run-time relationships between objects** (today)
|
||
- Aggregate vs. acquaintance
|
||
- **Delegation** (later...)
|
||
|
||
Next Time: Design Patterns
|
||
|
||
Describe the core of a repeatable solution to common design problems.
|
||
|
||
### Code Reuse: Two Ways to Reuse a Class
|
||
|
||
#### Inheritance
|
||
|
||
Code reuse by inheriting the implementation of a base class.
|
||
|
||
- **Pros:**
|
||
- Inheritance relationships defined at compile-time - simple to understand.
|
||
- **Cons:**
|
||
- Subclass often inherits some implementation from superclass - derived class now depends on its base class implementation, leading to less flexible code.
|
||
|
||
#### Composition
|
||
|
||
Assemble multiple objects together to create new complex functionality, forward requests to the responsible assembled object.
|
||
|
||
- **Pros:**
|
||
- Allows flexibility at run-time, composite objects often constructed dynamically by obtaining references/pointers to other objects (dependency injection).
|
||
- Objects known only through their interface - increased flexibility, reduced impact of change.
|
||
- **Cons:**
|
||
- Code can be more difficult to understand, how objects interact may change dynamically.
|
||
|
||
### Example: Our First Design Pattern (Adapter Pattern)
|
||
|
||
**Problem:** We are given a class that we cannot modify for some reason - it provides functionality we need, but defines an interface that does not match our program (client code).
|
||
|
||
**Solution:** Create an adapter class, adapter declares the interface needed by our program, defines it by forwarding requests to the unmodifiable object.
|
||
|
||
Two ways to do this:
|
||
|
||
```cpp
|
||
class unmodifiable {
|
||
public:
|
||
int func(); // does something useful, but doesn’t match the interface required by the client code
|
||
};
|
||
```
|
||
|
||
1. **Inheritance**
|
||
|
||
```cpp
|
||
// Using inheritance:
|
||
class adapter : protected unmodifiable {
|
||
// open the access to the protected member func() for derived class
|
||
public:
|
||
int myFunc() {
|
||
return func(); // forward request to encapsulated object
|
||
}
|
||
};
|
||
```
|
||
|
||
2. **Composition**
|
||
|
||
```cpp
|
||
class adapterComp {
|
||
unmodifiable var;
|
||
public:
|
||
int myFunc() {
|
||
return var.func();
|
||
}
|
||
};
|
||
```
|
||
|
||
### Thinking About and Describing Run-time Relationships
|
||
|
||
Typically, composition is favored over inheritance! Object composition with programming to an interface allows relationships/interactions between objects to vary at run-time.
|
||
|
||
- **Aggregate:** Object is part of another. Its lifetime is the same as the object it is contained in. (similar to base class and derived class relationship)
|
||
- **Acquaintance:** Objects know of each other, but are not responsible for each other. Lifetimes may be different.
|
||
|
||
```cpp
|
||
// declare Printable Interface
|
||
// declare printable interface
|
||
class printable {
|
||
public:
|
||
virtual void print(ostream &o) = 0;
|
||
};
|
||
// derived classes defines printable
|
||
// interface
|
||
class smiley : public printable {
|
||
public:
|
||
virtual void print(ostream &o) {
|
||
o << ":)";
|
||
};
|
||
};
|
||
// second derived class defines
|
||
// printable interface
|
||
class frown : public printable {
|
||
public:
|
||
virtual void print(ostream &o) {o << ":(";
|
||
};
|
||
};
|
||
```
|
||
|
||
1. **Aggregate**
|
||
|
||
```cpp
|
||
// implementation 1:
|
||
// Aggregate relationship
|
||
class emojis {
|
||
printable * happy;
|
||
printable * sad;
|
||
public:
|
||
emojis() {
|
||
happy = new smiley();
|
||
sad = new frown();
|
||
};
|
||
~emojis() {
|
||
delete happy;
|
||
delete sad;
|
||
};
|
||
};
|
||
```
|
||
|
||
2. **Acquaintance**
|
||
|
||
```cpp
|
||
// implementation 2:
|
||
// Acquaintances only
|
||
class emojis {
|
||
printable * happy;
|
||
printable * sad;
|
||
public:
|
||
emojis();
|
||
~emojis();
|
||
// dependency injection
|
||
void setHappy(printable *);
|
||
void setSad(printable *);
|
||
};
|
||
```
|