What ?
Definitions
Part 1: Abstraction provides a blueprint or plan for designing classes with a defined set of rules. It ensures consistency and enforces that certain behaviors are implemented across derived classes.
Part 2: Abstraction is the process of hiding implementation details from users, enabling them to focus on the functionality rather than the internal workings.
Eg: A commonly used analogy is the TV remote control: users interact with buttons to operate the TV without needing to know how the internal mechanics work.
I find Part 1 to be more intuitive and easy to explain so this post explains in detail Part 1 of the definition.
Part 2 is explained in detail here.
Why a blueprint?
To understand the need for abstraction (a blue print), let’s first explore a problem.
Problem:
Imagine creating classes to draw pictures of animals. Each animal has its own unique features, but certain traits—such as having four legs and a tail—are shared among them. Without a structured approach, developers might forget to include these common traits, leading to incomplete or inaccurate depictions.
class DogPicture {
drawATail() {}
drawFourLegs() {}
drawFloppyEars() {}
}
class CatPicture {
drawATail() {}
drawFourLegs() {}
drawConeShapedEars() {}
}
class HorsePicture {
drawATail() {}
drawFourLegs() {}
drawManeHair() {}
}
class GoatPicture {
drawATail() {}
drawFourLegs() {}
drawHorns() {}
}
class ZebraPicture {
drawATail() {}
drawFourLegs() {}
drawStripesOnBody() {}
}
Solution:
Abstraction can solve this problem by defining a shared plan or rules that every animal picture class must follow. This can be achieved using an abstract class or interface in TypeScript.
abstract class AnimalPicture {
abstract drawFourLegs(): void;
abstract drawATail(): void;
}
Now, any class that implements AnimalPicture must define these methods. Failing to do so will result in an error.
Incorrect implementation
class DogPicture implements AnimalPicture { // this will throw error as `drawFourLegs` & `drawATail` are not implemented.
drawFloppyEars() {}
}
Error:
Class 'DogPicture' incorrectly implements class 'AnimalPicture'. Did you mean to extend 'AnimalPicture' and inherit its members as a subclass?
Type 'DogPicture' is missing the following properties from type 'AnimalPicture': drawFourLegs, drawATailts(2720)
Correct implementation
class DogPicture implements AnimalPicture {
drawFourLegs(): void {
console.log("Drawing four legs for a dog.");
}
drawATail(): void {
console.log("Drawing four legs for a dog.");
}
drawFloppyEars() {}
}
class CatPicture implements AnimalPicture {
drawFourLegs(): void {
console.log("Drawing four legs for a cat.");
}
drawATail(): void {
console.log("Drawing four legs for a cat.");
}
drawConeShapedEars() {}
}
class HorsePicture implements AnimalPicture {
drawFourLegs(): void {
console.log("Drawing four legs for a horse.");
}
drawATail(): void {
console.log("Drawing four legs for a horse.");
}
drawManeHair() {}
}
class GoatPicture implements AnimalPicture {
drawFourLegs(): void {
console.log("Drawing four legs for a goat.");
}
drawATail(): void {
console.log("Drawing four legs for a goat.");
}
drawHorns() {}
}
class ZebraPicture implements AnimalPicture {
drawFourLegs(): void {
console.log("Drawing four legs for a zebra.");
}
drawATail(): void {
console.log("Drawing four legs for a zebra.");
}
drawStripesOnBody() {}
}
This ensures that all animal picture classes implement the shared rules (drawFourLegs and drawATail), while allowing flexibility for unique features like floppy ears or stripes.
Types of abstract classes:
- Pure abstract class
These classes are plain blueprints that won't have any concrete/implemented methods.
// pure abstract class
abstract class AnimalPicture {
abstract drawFourLegs(): void;
abstract drawATail(): void;
}
In Typescript these pure abstract classes (with no access privilege needs like protected) can be replaced with interfaces which is as well could as a blue print.
// interface
interface AnimalPicture {
drawFourLegs(): void;
drawATail(): void;
}
//usage
class HorsePicture implements AnimalPicture {
drawFourLegs(): void {
console.log("Drawing four legs for a horse.");
}
drawATail(): void {
console.log("Drawing four legs for a horse.");
}
drawManeHair() {}
}
- Impure/partial abstract class:
Abstract classes that have one or more concrete methods along with a few abstract attributes(methods/properties).
These classes can be extended(inherited) to create sub classes.
Defining the abstract class
// impure abstract class
abstract class AnimalPicture {
// Concrete method 1
protected drawFourLegs() {
console.log(`drawing common four legs feature`);
}
// Concrete method 2
protected drawATail() {
console.log(`drawing common tail feature`);
}
// Abstract method 1
protected abstract drawUniqueFeature(): void;
// Concrete method 3
public drawFinalPicture() {
this.drawATail();
this.drawFourLegs();
this.drawUniqueFeature();
}
}
Extending the abstract class
class DogPicture extends AnimalPicture {
// because its inheritance, calling the super/parent class is required.
constructor() {
super();
}
// Abstract method 1 implemented
protected drawUniqueFeature(): void {
console.log("Drawing four legs for a dog.");
}
}
Usage
const dog = new DogPicture();
// Concrete method 3 of abstract class is inherited
dog.drawFinalPicture();
Part1(abstract as blueprint) Conclusion
Abstraction in OOP helps enforce a consistent structure across related classes while allowing flexibility for unique implementations. It ensures that essential behaviors are not overlooked, making code more predictable and maintainable.
Also, please carryon reading the part2 post to understand the part2 of the definition.
Top comments (0)