Today's mission involves using multiple Object-Oriented Programming (OOP) principles to tackle complex tasks. When principles like Encapsulation, Abstraction, Polymorphism, and Composition are blended, the resulting code becomes streamlined and easier to manage.
Our goal is to dissect two real-world examples, gaining insights into how these principles can seamlessly orchestrate solutions.
Let's design an online library system, as we aim to reinforce our understanding of Encapsulation
and Polymorphism
. Encapsulation
will help us protect the attributes of books, members, and transactions, ensuring they are accessible in a controlled manner. Polymorphism
will demonstrate its power by enabling a single interface to represent different underlying forms, such as digital and print versions of books.
C#1using System; 2using System.Collections.Generic; 3 4// Base class for different types of library users 5class Member { 6 private string name; 7 8 public Member(string name) { 9 this.name = name; 10 } 11 12 public void CheckOutBook(Book book) { 13 Console.WriteLine($"{name} checked out {book.GetBookType()} book {book.Title}."); 14 } 15} 16 17// Base class for different types of books 18abstract class Book { 19 private string title; 20 21 public string Title { 22 get { return title; } 23 private set { title = value; } 24 } 25 26 public Book(string title) { 27 Title = title; 28 } 29 30 public abstract string GetBookType(); 31} 32 33// Inherits from Book, represents a digital book 34class DigitalBook : Book { 35 public DigitalBook(string title) : base(title) { } 36 37 public override string GetBookType() { 38 return "Digital"; 39 } 40} 41 42// Inherits from Book, represents a physical book 43class PhysicalBook : Book { 44 public PhysicalBook(string title) : base(title) { } 45 46 public override string GetBookType() { 47 return "Physical"; 48 } 49} 50 51// Library class that manages members and books 52class Library { 53 private List<Member> members; 54 private List<Book> books; 55 56 public Library() { 57 members = new List<Member>(); 58 books = new List<Book>(); 59 } 60 61 public void AddMember(Member member) { 62 members.Add(member); 63 } 64 65 public void AddBook(Book book) { 66 books.Add(book); 67 } 68} 69 70class Program { 71 static void Main(string[] args) { 72 Library myLibrary = new Library(); 73 74 Member alice = new Member("Alice"); 75 Member bob = new Member("Bob"); 76 77 myLibrary.AddMember(alice); 78 myLibrary.AddMember(bob); 79 80 Book digitalBook = new DigitalBook("The C# Handbook"); 81 Book physicalBook = new PhysicalBook("Learning C# Design Patterns"); 82 83 myLibrary.AddBook(digitalBook); 84 myLibrary.AddBook(physicalBook); 85 86 alice.CheckOutBook(digitalBook); // Prints: Alice checked out Digital book The C# Handbook. 87 bob.CheckOutBook(physicalBook); // Prints: Bob checked out Physical book Learning C# Design Patterns. 88 } 89}
In this code snippet, Encapsulation
is observed clearly through the class structures and the controlled access to their attributes. Polymorphism
is vividly illustrated by how both DigitalBook
and PhysicalBook
classes inherit from the Book
class but provide their own implementations of the GetBookType
method. This setup allows objects of DigitalBook
and PhysicalBook
to be used interchangeably when a book’s type needs to be identified, demonstrating polymorphism’s capability to work with objects of different classes through a common interface.
Encapsulation
ensures that details about members and books are well-contained within their respective classes.Polymorphism
showcases flexibility by treating different book types uniformly, making the system more adaptive and scalable.
Next, we'll develop a shape-drawing application capable of drawing various shapes. For this, we'll employ the principles of Abstraction
and Composition
.
Abstraction
simplifies the complexity associated with drawing different shapes.Composition
takes care of composite shapes.
Here's how we translate these principles into our shape-drawing application:
C#1using System; 2using System.Collections.Generic; 3 4// Define the basic Shape class 5abstract class Shape { 6 // Abstract method that will be implemented in each subclass 7 public abstract void Draw(); 8} 9 10// Define the Circle class 11class Circle : Shape { 12 // Implement the draw method for circle 13 public override void Draw() { 14 Console.WriteLine("Drawing a circle."); 15 } 16} 17 18// Define the Square class 19class Square : Shape { 20 // Implement the draw method for square 21 public override void Draw() { 22 Console.WriteLine("Drawing a square."); 23 } 24} 25 26// Define the ShapeComposite class 27class ShapeComposite : Shape { 28 // Initialize with an empty list of shapes 29 private List<Shape> shapes; 30 31 public ShapeComposite() { 32 shapes = new List<Shape>(); 33 } 34 35 // Add a new shape to the composite 36 public void AddShape(Shape shape) { 37 shapes.Add(shape); 38 } 39 40 // Implement the draw method to draw each shape in the composite 41 public override void Draw() { 42 foreach (Shape shape in shapes) { 43 shape.Draw(); 44 } 45 } 46} 47 48class Program { 49 static void Main(string[] args) { 50 Circle circle = new Circle(); 51 Square square = new Square(); 52 53 // Drawing individual shapes 54 circle.Draw(); // Output: Drawing a circle. 55 square.Draw(); // Output: Drawing a square. 56 57 // Create a ShapeComposite instance for composite shapes 58 ShapeComposite compositeShape = new ShapeComposite(); 59 60 // Add individual shapes to the composite 61 compositeShape.AddShape(circle); 62 compositeShape.AddShape(square); 63 64 // Drawing the composite shape 65 compositeShape.Draw(); 66 // Output: 67 // Drawing a circle. 68 // Drawing a square. 69 } 70}
- Abstraction: In this example, the
Shape
class is abstract. We don’t care about the specific details of how each shape is drawn here, but we know that each shape must have aDraw()
method. The abstract class helps us define this rule for all shapes. - Composition: The
ShapeComposite
class demonstrates composition by combining multiple shapes. It can hold and draw multiple shapes together. Composition is used when one object (a composite shape) contains other objects (individual shapes).
Well done! You combined multiple OOP principles to respond to complex tasks. By dissecting real-world examples, we understood how these principles found their applications. Now, it's time to put this knowledge to work. Practice fortifies concepts, transforming knowledge into expertise. So, let's get coding!