In
object-oriented programming theory,
abstraction involves the facility to define objects that represent abstract "actors" that can perform work, report on and change their state, and "communicate" with other objects in the system. The term
encapsulation refers to the hiding of
state details, but extending the concept of
data type from earlier programming languages to associate
behavior most strongly with the data, and standardizing the way that different data types interact, is the beginning of
abstraction. When abstraction proceeds into the operations defined, enabling objects of different types to be substituted, it is called
polymorphism. When it proceeds in the opposite direction, inside the types or classes, structuring them to simplify a complex set of relationships, it is called
delegation or
inheritance. Various object-oriented programming languages offer similar facilities for abstraction, all to support a general strategy of
polymorphism in object-oriented programming, which includes the substitution of one
data type for another in the same or similar role. Although not as generally supported, a
configuration or image or package may predetermine a great many of these
bindings at
compile time,
link time, or
load time. This would leave only a minimum of such bindings to change at
run-time.
Common Lisp Object System or
Self, for example, feature less of a class-instance distinction and more use of delegation for
polymorphism. Individual objects and functions are abstracted more flexibly to better fit with a shared functional heritage from
Lisp. C++ exemplifies another extreme: it relies heavily on
templates and
overloading and other static bindings at compile-time, which in turn has certain flexibility problems. Although these examples offer alternate strategies for achieving the same abstraction, they do not fundamentally alter the need to support abstract nouns in code – all programming relies on an ability to abstract verbs as functions, nouns as data structures, and either as processes. Consider for example a sample
Java fragment to represent some common farm "animals" to a level of abstraction suitable to model simple aspects of their hunger and feeding. It defines an Animal class to represent both the state of the animal and its functions: public class Animal extends LivingThing { private Location loc; private double energyReserves; public boolean isHungry() { return energyReserves With the above definition, one could create objects of type and call their methods like this: thePig = new Animal(); theCow = new Animal(); if (thePig.isHungry()) { thePig.eat(tableScraps); } if (theCow.isHungry()) { theCow.eat(grass); } theCow.moveTo(theBarn); In the above example, the class
Animal is an abstraction used in place of an actual animal,
LivingThing is a further abstraction (in this case a generalisation) of
Animal. If one requires a more differentiated hierarchy of animals – to differentiate, say, those who provide milk from those who provide nothing except meat at the end of their lives – that is an intermediary level of abstraction, probably DairyAnimal (cows, goats) who would eat foods suitable to giving good milk, and MeatAnimal (pigs, steers) who would eat foods to give the best meat-quality. Such an abstraction could remove the need for the application coder to specify the type of food, so they could concentrate instead on the feeding schedule. The two classes could be related using
inheritance or stand alone, and the programmer could define varying degrees of
polymorphism between the two types. These facilities tend to vary drastically between languages, but in general each can achieve anything that is possible with any of the others. A great many operation overloads, data type by data type, can have the same effect at compile-time as any degree of inheritance or other means to achieve polymorphism. The class notation is simply a coder's convenience.
Object-oriented design Decisions regarding what to abstract and what to keep under the control of the coder become the major concern of object-oriented design and
domain analysis—actually determining the relevant relationships in the real world is the concern of
object-oriented analysis or
legacy analysis. In general, to determine appropriate abstraction, one must make many small decisions about scope (domain analysis), determine what other systems one must cooperate with (legacy analysis), then perform a detailed object-oriented analysis which is expressed within project time and budget constraints as an object-oriented design. In our simple example, the domain is the barnyard, the live pigs and cows and their eating habits are the legacy constraints, the detailed analysis is that coders must have the flexibility to feed the animals what is available and thus there is no reason to code the type of food into the class itself, and the design is a single simple Animal class of which pigs and cows are instances with the same functions. A decision to differentiate DairyAnimal would change the detailed analysis but the domain and legacy analysis would be unchanged—thus it is entirely under the control of the programmer, and it is called an abstraction in object-oriented programming as distinct from abstraction in domain or legacy analysis. ==Considerations==