Introduction
Delegation is an object-oriented design pattern in which an object passes a task to another object instead of performing it itself. This concept allows for polymorphism and code reuse, leading to more maintainable and flexible code. Delegation helps maintain a loosely coupled system, which is easier to maintain and extend.
Table of Contents
- What is Delegation?
- Benefits of Delegation
- Example 1: Ticket Booking System
- Example 2: Printers Implementation
- Conclusion
1. What is Delegation?
Delegation is a technique in which an object delegates responsibilities to another helper object. Instead of doing the work itself, it passes the task to another object. This helps achieve polymorphism and ensures that tasks are handled by the most appropriate class.
2. Benefits of Delegation
- Loosely Coupled Code: Delegation reduces the coupling between classes.
- Code Reusability: Common functionalities can be reused by multiple classes.
- Enhanced Flexibility: Changes to the delegated class do not affect the delegator class.
- Improved Maintainability: Easier to maintain and extend as the code is modular.
3. Example 1: Ticket Booking System
Step-by-Step Implementation
Step 1: Create a TravelBooking Interface
interface TravelBooking {
void bookTicket();
}
The TravelBooking
interface defines a single method bookTicket()
, which will be implemented by various travel booking classes.
Step 2: TrainBooking Class
class TrainBooking implements TravelBooking {
@Override
public void bookTicket() {
System.out.println("Train ticket booked");
}
}
The TrainBooking
class implements the TravelBooking
interface and provides a specific implementation for booking train tickets.
Step 3: AirBooking Class
class AirBooking implements TravelBooking {
@Override
public void bookTicket() {
System.out.println("Flight ticket booked");
}
}
The AirBooking
class implements the TravelBooking
interface and provides a specific implementation for booking air tickets.
Step 4: TicketBookingByAgent Class
class TicketBookingByAgent implements TravelBooking {
private TravelBooking travelBooking;
public TicketBookingByAgent(TravelBooking travelBooking) {
this.travelBooking = travelBooking;
}
@Override
public void bookTicket() {
travelBooking.bookTicket();
}
}
The TicketBookingByAgent
class also implements the TravelBooking
interface but delegates the actual booking task to another TravelBooking
object. The delegation is achieved via the constructor which accepts a TravelBooking
object. The bookTicket()
method calls the bookTicket()
method of the delegated TravelBooking
object.
Step 5: DelegationDemonstration Class
public class DelegationDemonstration {
public static void main(String[] args) {
TicketBookingByAgent agent = new TicketBookingByAgent(new TrainBooking());
agent.bookTicket(); // Output: Train ticket booked
agent = new TicketBookingByAgent(new AirBooking());
agent.bookTicket(); // Output: Flight ticket booked
}
}
In the DelegationDemonstration
class, we create an instance of TicketBookingByAgent
and pass it different TravelBooking
implementations. The bookTicket()
method of TicketBookingByAgent
delegates the call to the appropriate booking class (either TrainBooking
or AirBooking
).
How Delegation Works in the Ticket Booking System
In this example, the TicketBookingByAgent
class does not handle the actual ticket booking process. Instead, it delegates this responsibility to the classes that implement the TravelBooking
interface (TrainBooking
and AirBooking
). This allows TicketBookingByAgent
to dynamically choose which booking implementation to use at runtime, promoting flexibility and code reuse.
4. Example 2: Printers Implementation
Step-by-Step Implementation
Step 1: Printer Interface
public interface Printer {
void print(String message);
}
The Printer
interface defines a single method print()
, which will be implemented by various printer classes.
Step 2: CanonPrinter Class
public class CanonPrinter implements Printer {
@Override
public void print(String message) {
System.out.println("Canon Printer: " + message);
}
}
The CanonPrinter
class implements the Printer
interface and provides a specific implementation for printing a message.
Step 3: EpsonPrinter Class
public class EpsonPrinter implements Printer {
@Override
public void print(String message) {
System.out.println("Epson Printer: " + message);
}
}
The EpsonPrinter
class implements the Printer
interface and provides a specific implementation for printing a message.
Step 4: HpPrinter Class
public class HpPrinter implements Printer {
@Override
public void print(String message) {
System.out.println("HP Printer: " + message);
}
}
The HpPrinter
class implements the Printer
interface and provides a specific implementation for printing a message.
Step 5: PrinterController Class
public class PrinterController implements Printer {
private final Printer printer;
public PrinterController(Printer printer) {
this.printer = printer;
}
@Override
public void print(String message) {
printer.print(message);
}
}
The PrinterController
class also implements the Printer
interface but delegates the actual printing task to another Printer
object. The delegation is achieved via the constructor which accepts a Printer
object. The print()
method calls the print()
method of the delegated Printer
object.
Step 6: App Class to Test Delegation
public class App {
public static final String MESSAGE_TO_PRINT = "hello world";
public static void main(String[] args) {
PrinterController hpPrinterController = new PrinterController(new HpPrinter());
PrinterController canonPrinterController = new PrinterController(new CanonPrinter());
PrinterController epsonPrinterController = new PrinterController(new EpsonPrinter());
hpPrinterController.print(MESSAGE_TO_PRINT); // Output: HP Printer: hello world
canonPrinterController.print(MESSAGE_TO_PRINT); // Output: Canon Printer: hello world
epsonPrinterController.print(MESSAGE_TO_PRINT); // Output: Epson Printer: hello world
}
}
How Delegation Works in the Printers Implementation
In this example, the PrinterController
class does not handle the actual printing process. Instead, it delegates this responsibility to the classes that implement the Printer
interface (CanonPrinter
, EpsonPrinter
, and HpPrinter
). This allows PrinterController
to dynamically choose which printer implementation to use at runtime, promoting flexibility and code reuse.
5. Conclusion
Delegation is a powerful design pattern that allows objects to delegate tasks to other objects, promoting code reuse and modularity. By using delegation, you can create more flexible and maintainable systems. In this article, we explored two examples: a ticket booking system and a printer implementation, to demonstrate how delegation can be effectively used in Java.
Happy coding!
class diagram is wrong. +CanonPrinter() in all the different printer class
ReplyDeleteClass diagram is not wrong. The content CononPrinter is typo in all subclasses.You can fix this.
DeleteThis typo has fixed , thanks for informing.
ReplyDelete