Object Oriented Programming

From Wikibooks, open books for an open world
Jump to navigation Jump to search


Object Oriented Programming (OOP) means any kind of programming that uses a programming language with some object oriented constructs or programming in an environment where some object oriented principles are followed. At its heart, though, object oriented programming is a mindset which respects programming as a problem-solving dilemma on a grand scale which requires careful application of abstractions and subdividing problems into manageable pieces. Compared with procedural programming, a superficial examination of code written in both styles would reveal that object oriented code tends to be broken down into vast numbers of small pieces, with the hope that each piece will be trivially verifiable. OOP was one step towards the holy grail of software-re-usability, although no new term has gained widespread acceptance, which is why "OOP" is used to mean almost any modern programming distinct from systems programming, assembly programming, functional programming, or database programming. Modern programming would be better categorized as "multi-paradigm" programming, and that term is sometimes used. This book is primarily aimed at modern, multi-paradigm programming, which has classic object oriented programming as its immediate predecessor and strongest influence.

Historically, "OOP" has been one of the most influential developments in computer programming, gaining widespread use in the mid 1980s. Originally heralded for its facility for managing complexity in ever-growing software systems, OOP quickly developed its own set of difficulties. Fortunately, the ever evolving programming landscape gave us "interface" programming, design patterns, generic programming, and other improvements paving the way for more contemporary Multi-Paradigm programming. While some people will debate endlessly about whether or not a certain language implements "Pure" OOP—and bless or denounce a language accordingly—this book is not intended as an academic treatise on object oriented programming or its theory.

Instead, we aim for something more pragmatic: we start with basic OO theory and then delve into a handful of real-world languages to examine how they support OO programming. Since we obviously cannot teach each language, the point is to illustrate the trade-offs inherent in different approaches to OOP.

Introduction[edit]

Click "Introduction" to read more!

Classes, Types, and Classic OOP

Classes and Types page- Click link above to accesss.

"State" is Evil!

"State is evil" link above.

Inheritance

In many books, inheritance and OOP are made to seem synonymous, so it may seem strange that we deferred this discussion so far. This is a reflection of the diminished role of inheritance over time. In fact, one of the primary distinctions between Classic and Modern OOP lies in the usage of inheritance. As the old adage goes, if all you have is a hammer, then everything looks like a nail. And so it happened that often times, inheritance was the only tool available to the erstwhile OOP programmer, and so every concept under the sun (or at least the ghostly glow of a CRT) was crammed into inheritance. This lack of conceptual integrity and separation of concerns led to over-intimate dependencies and many difficulties. In some languages, programmer technique evolved to make the concepts clearer using the same limited language functions, while other languages explicitly developed features to address these concerns. Because you are almost certain to be exposed to some of this misguided advice at some point in your OOP learning, we'll try and explain some of the problems to you. However, much of the discussion will go in the sections where they properly belong!

First off, though, what is inheritance? Well, just like when your grandma dies and you inherit that gawd-awful ugly lamp, inheritance in OOP grants the child-class (or derived-class) all of the attributes of the parent (or super) class. So, for example (in C++):

class Parent
{
public:
   int f() {return 10;}
};
class Child : public Parent
{
// see, nothing here!  But wait, we inherited the function f()!
};
Child c;
int result = c.f();  // huh?  Oh, f() was inherited from the parent!

Is-A vs Has-A Moley Baloney[edit]

The most over-used and rather worthless discussion on inheritance that you will see revolves around the "Is-A vs Has-A" discussion. For example, a car is-a vehicle but has-a steering wheel. The idea these authors are chasing is that your car class should inherit your vehicle class and have a steering wheel as a member. You might also run across examples with shapes, where a Rectangle is-a Shape. The point is, once again, abstraction. The goal is to identify operations that operate only on the abstract notion of vehicle or shape and then write that code only once. Then, through the magic of inheritance, you can pass in cars or rectangles or what-have-you to the generic code, and it will work, since the derived classes are everything the parent classes are, "plus more".

The problem here is that inheritance is mixing together several things: you inherit "typeness", interface, and implementation all at the same time. However, all of the examples focus on interface while talking about "typeness". The abstract code doesn't care that a car "is-a" vehicle, just that the objects respond to a certain set of functions, or interface. In fact, if you want to give your chair class accelerate(), brake(), turn_left() and turn_right() methods, shouldn't the abstract code be able to work on chairs then? Well, of course, but that doesn't make chairs vehicles.

The kinds of solutions proposed in these "is-a" discussions have thus been mostly replaced by so-called interface programming and template programming. Since template programming offers the loosest coupling, it focused some attention on the syntactic-semantic confusion. Just because you have functions with the proper names, does that mean that they do what you think they do? If a chair class has accelerate(), brake() and other vehicle type methods, does it make sense to have generic vehicle code work on this chair? This led to more codifying of the assumptions of generic code: say, brake(INFINITY) ==> STOPPED. This implies that brake(x) != accelerate(-x). So chair may make a better vehicle than the Starship Enterprise!

Delegation and "Dynamic Inheritance"[edit]

You will see more about delegation later in the section on message passing, but we wanted to mention that many problems solved by delegation are often tackled by inheritance in languages that don't offer a delegation feature. It's easier to show an example than explain, so in short, here's what delegation looks like:

interface I
{
   int f();
}
class A implements I
{
   // A member variable that actually services all requests for
   //  calls to the I interface.
   delegate I private_i;

   A(I target)
   {
       private_i = target;
   }
}
class B implements I
{
   int f() { return 1; }
}
B b;  // create a B object to be the target of A's delegation
A a(b);  // Create an A object, passing in b

int foo = a.f();  // This call to f() is delegated to b.f(), causing 1 to be returned.

Inheritance accomplishes a similar feat

class B
{
   int f() { return 1; }
}
class A inherits B
{
}
A a;

int foo = a.f();  // returns 1 just like in the delegation example.

However, the delegate can change over time, whereas base classes cannot. As a result, sometimes delegation is referred to as "dynamic inheritance".


Multiple Inheritance[edit]

Multiple inheritance is where an object inherits its properties from many different classes. For example, a house is both a "building" and a "place to sleep in".

In multiple inheritance, an object inherits its properties from many objects (its parents or base classes). Therefore, we need to set up some classes, which we will use C++ for:

class Building
{
  int size;
  int purpose;
  int price;
};
class PlaceToSleepIn
{
  int type; // tent, house, dorm, etc.
  bool pleasant_to_live_in; // true or false
};

In C++, to inherit all the types, one uses the : operator, like so:

class House : public Building, public PlaceToSleepIn
{
  // all of the Building and PlaceToSleepIn variables are here!
  int rooms; // the number of rooms
};

Problems with Inheritance[edit]

One problem of Inheritance is that users of predefined classes may not know the location of the abstracted data. Therefore, it may not be easy for them to obtain it. Most of the problems with inheritance is due to design fragility or issues with the way a programming language implements it.

A normal issue in dealing with inheritance in large programs is called Fragile Base Class. It arises when subclasses of the base class make assumptions about the property (the definition of the attribute) that are outside the contract provided by the base class.

An example could be of an attribute that was declared in the base class as byte but later turns out to need the range of word. Changing this to word will necessitate at least recompiling all sub-classes but that might well not be enough because the sub-classes might have relied on the type of this attribute so that the source code also will need to be changed.

This intrinsic knowledge of the implementor about a given implementation is a problem in general programming but one that OOP/OOD does attempt to solve by offering greater opportunities for better programming practices. But as anything else with code it is up for the programmer to make use of it as to be as transparent as possible as to enable other to take full advantage of its code and so of the property of inheritance.

Object/Relational Mappings[edit]

Separation of Static and Dynamic[edit]

Systems Architecture[edit]

(Logical) Networks[edit]

The Benefits of Static Analysis[edit]

Provable Correctness[edit]

Dealing With Hierarchies[edit]

Deep Single-Rooted Hierarchy[edit]

Shallow, Multi-Rooted Hierarchies[edit]

Traditional Neglect of Dynamic Analysis[edit]

Data Flow Diagrams[edit]

Interfaces and Components[edit]

Messages, Protocols and Dispatch[edit]

Synchronous vs Asynchronous[edit]

Delegation[edit]

Virtualization and Polymorphism[edit]

Polymorphism means the ability to take more than one form, that is one name,multiple forms. In oops,an operation may exhibit different behaviour in different instances. The concept of polymorphism is implemented using function overloading and operator overloading.

Interfaces[edit]

Introduction[edit]

An Interface allows a class to expose a different set of properties and methods depending on context. For example, say that you were writing a Visual Basic 2005 application that manages clients. A client could be an individual person, or an organization. Part of the program generates address labels for clients.

You might define a person like this:

Class Person
    Public LastName As String
    Public FirstName As String
    Public Address As String
End Class

You might also define an Organization like this:

Class Organization
    Public Name As String
    Public MailingAddress As String
    Public BuildingAddress As String
End Class

As you can see, the main differences between a Person and an Organization are:

  • a Person has both a first name and a last name, while an organization has only a single name
  • an Organization has a separate mailing address, while a Person only has one address

So that you can have the one routine to print address labels, you create an interface called "IAddressLabel" (by convention, the name of an interfaces should start with a capital I).

Interface IAddressLabel
    ReadOnly Property Name() As String
    ReadOnly Property Address() As String
End Interface

You now change the Person class to implement this interface. The main thing to notice is that the Person's first and last names are combined on the label.

Class Person
    Implements IAddressLabel
    Public LastName As String
    Public FirstName As String
    Public Address As String
    Public ReadOnly Property Address1() As String Implements IAddressLabel.Address
        Get
            Return Address
        End Get
    End Property
    Public ReadOnly Property Name() As String Implements IAddressLabel.Name
        Get
            Return FirstName & " " & LastName 'combine the first and last names for the address label
        End Get
    End Property
End Class

You now change the Organization class to implement the IAddressLabel interface. Notice that the address for the label is the mailing address, not the building address.

Class Organization
    Implements IAddressLabel
    Public Name As String
    Public MailingAddress As String
    Public BuildingAddress As String
    Public ReadOnly Property Address() As String Implements IAddressLabel.Address
        Get
            Return MailingAddress 'Use the mailing address for the address label
        End Get
    End Property
    Public ReadOnly Property Name1() As String Implements IAddressLabel.Name
        Get
            Return Name
        End Get
    End Property
End Class

Now you can group the disparate objects together as a collection of address labels!

Sub Main()
    'create a person object
    Dim Bill As New Person
    Bill.FirstName = "William"
    Bill.LastName = "Jones"
    Bill.Address = "123 Test Rd Testville 9123"
    'create another person object
    Dim Sally As New Person
    Sally.FirstName = "Sally"
    Sally.LastName = "Smith"
    Sally.Address = "999 Sample Ave Testburg 9222"
    'create an Organization object
    Dim WidgetsInc As New Organization
    WidgetsInc.Name = "Widgets Incorporated"
    WidgetsInc.BuildingAddress = "9123 Avenue Rd Sampletown 9876"
    WidgetsInc.MailingAddress = "P.O. Box 123 Sampletown 9876"
    'Because all three objects implement the IAddressLabel interface, we can put them in the same array
    Dim MailingList(2) As IAddressLabel
    MailingList(0) = Bill
    MailingList(1) = Sally
    MailingList(2) = WidgetsInc
    'loop through, displaying the address label for each object
    Dim i As Integer
    For i = 0 To 2
        MsgBox(MailingList(i).Name & vbCrLf & MailingList(i).Address)
    Next i
End Sub

Interfaces vs. Inheritance[edit]

Interfaces and Inheritance can both be used to solve the problem of treating dissimilar objects collectively. For example, if you have a Cat class and a Dog class, but have some routine that needs to process them together, you could either:

  • Create an Animal base class, which contains procedures common to both Cats and Dogs, and have Cat and Dog inherit from Animal, or
  • Create an IAnimal interface, and have both Cat and Dog implement the interface.

Which approach to use depends on several factors. In general:

  • If you are extending an existing class, then use inheritance. For example, if you already have an Animal class, and then discover a need to distinguish between Cats and Dogs
  • If you are simply wanting to treat different objects as the same, then use Interfaces. For example, you already have Cat and Dog classes, and then discover a need to manipulate them in a similar fashion

The introduction of Components[edit]

Delegation[edit]

Inheritance vs Delegation[edit]

Dynamic Inheritance[edit]

Lifetime Management[edit]

Manual Lifetime Management[edit]

Factories[edit]

In the real world, factories are used to make stuff (e.g. automobiles). In OO programming, factories also make stuff; specifically, OO factories "make" (instantiate) objects.

At least in Java, a constructor is unable to return a reference to an existing object—it MUST return a brand-new object. This can cause two problems—too many object instances, and identical objects that are duplicates—not the exact same object.

Factories are generally implemented as a public static method inside a class that has only private constructors. In this way, only the factory can create instances "Guaranteeing[1]" that all instances of the object have been created by the factory.

The factory most often has an internal "Cache" of objects. Whenever a user asks the factory for a new object, the cache is consulted first and one of the cached objects are returned if it is identical—otherwise a new instance is created, added to the cache and returned.

Factories can also be used to inject user code into an "Unmodifiable" library. It is possible to save and restore a user object that implements some important functions of a library object. The library then uses that factory to get instances of the users object, and doesn't even know that the user has replaced a core component with completely new code.

As an example... Say the library uses Library objects all over the place. The library user can create a class (let's call it User) that extends Library. The user then calls LibraryFactory.set(User.class), and the factory stores it. Inside the library, whenever the library wishes to use a Library object, it calls the LibraryFactory.Factory() function to get a new instance. Without changing any code, the user can now completely change the way the library functions by overriding one or more methods in his User class.

This is used in various places inside the Java SDK to allow you to change how chunks of the SDK works without rewriting any of the code.

  1. In Java, just having private constructors does not truly guarantee that all your objects came from the factory. Serialization and reflection can still create new instances without going through the constructor.

Reference Counting[edit]

Garbage Collection[edit]

Garbage collection refers to freeing of heap-allocated memory. The heap memory must be freed eventually. Either the programmers code must explicitly free it, or some automatic system mechanism is required.

The most common mechanism is mark and sweep. This is where the system knows of certain top-level classes (Threads and windows mostly). It follows all the references from these "Known" classes to every class that can be reached and marks each class. When it's done, it "sweeps" (gets rid of) every unmarked class.

Garbage Collection is a huge enabler of Object Oriented development—it completely changes the way you design. With code-based memory management it is necessary to have some way to track an object. If it is created on the stack, it will be deleted when the method exits (so instances passed outside your method will become invalid). If it is created on the heap, some object must delete it manually—so if your method is going to create an object and pass it to two other objects that both retain the object, you have a problem. Who deletes the object? The original method can't because it will have exited before the two objects are finished with it, and the two objects shouldn't know anything about each other.

This type of problem is often solved with "Reference counting" which is another form of garbage collection, but a manual one. It also leads to fewer long-lived, free-roaming classes being created since they have to be tracked.

GC solves problem, that of ownership. If you are programming in a language with Garbage Collection, you may create classes on the fly, pass them off, retain a copy or forget about it... You really can't go wrong. When all instances have been "Forgotten", the class disappears.

The drawback is that GC tends to take a solid chunk of time. This is less true lately as at least Java has threaded GC and the ability to limit the amount of time GC will run. There are actually dozens of tuning and reporting options and the ability to select from multiple GC systems to fit your need.

GC Implementations run from trivial (instance counting) to amazingly complex. The current default Java VM uses a multi-tiered system with different mechanisms for new, middle-aged and old objects. For instance, since almost all new objects tend to die almost instantly, the first section (Eden) is divided in half. When one half becomes full, the currently referenced objects are copied to the other side. The system switches to using the "new" side and completely forgets about the old half. There is no explicit code invoked to delete objects that are already gone.

This means that GC can actually be more efficient than traditional allocation/free since there is no free operation for nearly all objects.

Garbage collection should be considered essential to OO Design.

Persistence[edit]

Persistence is simply the act of having objects that "Stick around" between invocations of your program.

This can be trivial (Just serializing an object out when exiting, serializing it back in when loading) to a full OO-database implementation.

Hibernate is a good program that sits between your application and a database and ensures that your objects are properly persisted.

Serialization[edit]

Serialization is converting an object to a stream of bytes that can then be saved to a file or transmitted over a network.

Generic Programming[edit]

Proxies[edit]

Abstracting Classes[edit]

In this article along with the demo project I will discuss Interfaces versus Abstract classes. The concept of Abstract classes and Interfaces is a bit confusing for beginners of Object Oriented programming. Therefore, I am trying to discuss the theoretical aspects of both the concepts and compare their usage. And finally I will demonstrate how to use them with C#.

Abstracting Algorithms[edit]

The Significance of Uniformity[edit]

Abstraction Barrier[edit]

The Introduction of Functional Programming Ideas[edit]

Functions as "True Citizens"[edit]

Closures[edit]

See also[edit]