- Java Guides
- Problem
- Forces
- Solution
- Structure
- Class Diagram
- Sequence Diagram
- Participants and Responsibilities
- Implementation
- Applicability
- References
- Related Patterns
- 1. Overview
- Applicability
- 2. Implementation with Examples
- Example 1: Let’s take the Ticket Booking example
- Example 2: Printers Implementation Example
- Pro Java
Java Guides
The Business Delegate pattern adds an abstraction layer between presentation and business tiers. By using the pattern we gain loose coupling between the tiers and encapsulate knowledge about how to locate, connect to, and interact with the business objects that make up the application.
Let’s discuss how Business Delegate Pattern decouples presentation tier and business tier with a class diagram and source code.
This pattern is divided into a number of sections for simplicity like problem, forces, solution etc.
Table of contents |
---|
Problem |
Forces |
Solution |
Structure — Class Diagram, Sequence Diagram |
Participants and Responsibilities |
Implementation |
Consequences |
Applicability |
References |
Problem
You want to hide clients from the complexity of remote communication with business service components.
Forces
(This section describes Lists the reasons and motivations that affect the problem and the solution. The list of forces highlights the reasons why one might choose to use the pattern and provides a justification for using the pattern)
- You want to access the business-tier components from your presentation-tier components and clients, such as devices, web services, and rich clients.
- You want to minimize coupling between clients and the business services, thus hiding the underlying implementation details of the service, such as lookup and access.
- You want to avoid unnecessary invocation of remote services.
- You want to translate network exceptions into application or user exceptions.
- You want to hide the details of service creation, reconfiguration, and invocation retries from the clients.
Solution
(Here solution section describes the solution approach briefly and the solution elements in detail)
Use a Business Delegate to encapsulate access to a business service. The Business Delegate hides the implementation details of the business service, such as lookup and access mechanisms.
Structure
Let’s use UML class diagram to show the basic structure of the solution and the UML Sequence diagram in this section present the dynamic mechanisms of the solution.
Class Diagram
Sequence Diagram
Participants and Responsibilities
BusinessDelegate — The BusinessDelegate’s role is to provide control and protection for the business service.
ServiceLocator — The ServiceLocator encapsulates the implementation details of locating a BusinessService component.
BusinessService — The BusinessService is a business-tier component, such as an enterprise bean, that is being accessed by the client.
Implementation
public interface BusinessService < void doProcessing(); >
public class EJBService implements BusinessService < @Override public void doProcessing() < System.out.println("EJBService is now processing"); > >
//This is Service JMS implementation. public class JMSService implements BusinessService < @Override public void doProcessing() < System.out.println("JMSService is now processing"); > >
//Service Email implementation. public class EmailService implements BusinessService @Override public void doProcessing() System.out.println("EmailService is now processing"); > >
This class acts as ServiceLocator encapsulates the implementation details of locating BusinessService components.
public class BusinessLookup < private EjbService ejbService; private JmsService jmsService; private EmailService emailService; /** * @param serviceType * Type of service instance to be returned. * @return Service instance. */ public BusinessService getBusinessService(ServiceType serviceType) < if (serviceType.equals(ServiceType.EJB)) < return ejbService; > else if (serviceType.equals(ServiceType.JMS)) < return jmsService; > else < return emailService; > > public void setJmsService(JmsService jmsService) < this.jmsService = jmsService; > public void setEjbService(EjbService ejbService) < this.ejbService = ejbService; > public void setEmailService(EmailService emailService) < this.emailService = emailService; > >
public class BusinessDelegate < private BusinessLookup lookupService; private BusinessService businessService; private ServiceType serviceType; public void setLookupService(BusinessLookup businessLookup) < this.lookupService = businessLookup; > public void setServiceType(ServiceType serviceType) < this.serviceType = serviceType; > public void doTask() < businessService = lookupService.getBusinessService(serviceType); businessService.doProcessing(); > > Enumeration of service types public enum ServiceType < EJB, JMS,EMAIL; >
Step 5: Create Client. The client utilizes BusinessDelegate to call the business tier.
public class Client < private BusinessDelegate businessDelegate; public Client(BusinessDelegate businessDelegate) < this.businessDelegate = businessDelegate; > public void doTask() < businessDelegate.doTask(); > >
Step 6 : Use BusinessDelegate and Client classes to demonstrate Business Delegate pattern.
In this example, the client utilizes a business delegate to execute a task. The Business Delegate then selects the appropriate service and makes the service call.
public class App < /** * Program entry point. * * @param args command line args */ public static void main(String[] args) < BusinessDelegate businessDelegate = new BusinessDelegate(); BusinessLookup businessLookup = new BusinessLookup(); businessLookup.setEjbService(new EjbService()); businessLookup.setJmsService(new JmsService()); businessLookup.setEmailService(new EmailService()); businessDelegate.setLookupService(businessLookup); businessDelegate.setServiceType(ServiceType.EJB); Client client = new Client(businessDelegate); client.doTask(); businessDelegate.setServiceType(ServiceType.JMS); client.doTask(); businessDelegate.setServiceType(ServiceType.EMAIL); client.doTask(); > >
Applicability
- you want loose coupling between presentation and business tiers
- you want to orchestrate calls to multiple business services
- you want to encapsulate service lookups and service calls
References
Related Patterns
1. Overview
It is a technique where an object expresses certain behavior to the outside but in reality delegates responsibility for implementing that behaviour to an associated object.
Applicability
- Reduce the coupling of methods to their class
- Components that behave identically, but realize that this situation can change in the future.
- If you need to use functionality in another class but you do not want to change that functionality then use delegation instead of inheritance.
2. Implementation with Examples
Example 1: Let’s take the Ticket Booking example
interface TravelBooking < public void bookTicket(); >
class TrainBooking implements TravelBooking < @Override public void bookTicket() < System.out.println("Train ticket booked"); > >
class AirBooking implements TravelBooking < @Override public void bookTicket() < System.out.println("Flight ticket booked"); > >
Step 4: TicketBokkingByAgent provides an implementation of TravelBooking. But it delegates actual ticket booking to other classes at runtime using Polymorphism.
class TicketBookingByAgent implements TravelBooking < TravelBooking t; public TicketBookingByAgent(TravelBooking t) < this.t = t; > // Delegation --- Here ticket booking responsibility // is delegated to other class using polymorphism @Override public void bookTicket() < t.bookTicket(); > >
public class DelegationDemonstration < public static void main(String[] args) < // Here TicketBookingByAgent class is internally // delegating train ticket booking responsibility to other class TicketBookingByAgent agent = new TicketBookingByAgent(new TrainBooking()); agent.bookTicket(); agent = new TicketBookingByAgent(new AirBooking()); agent.bookTicket(); > >
Example 2: Printers Implementation Example
In this example, the delegates are CanonPrinter, EpsonPrinter, or HpPrinter they all implement Printer. The PrinterController is a delegator class that also implements Printer.
PrinterController is not responsible for the actual desired action but is actually delegated to a helper class either CanonPrinter, EpsonPrinter, or HpPrinter. The consumer does not have or require knowledge of the actual class carrying out the action, only the container on which they are calling.
Step 1: First create a Printer interface that both the Controller and the Delegate classes will implement.
public interface Printer < void print(final String message); >
Step 2: Specialised Implementation of Printer for a CanonPrinter, in this case, the message to be printed is appended to «Canon Printer: «.
public class CanonPrinter implements Printer < private static final Logger LOGGER = LoggerFactory.getLogger(CanonPrinter.class); @Override public void print(String message) < LOGGER.info("Canon Printer : <>", message); > >
Step 3: Specialized Implementation of Printer for an Epson Printer, in this case, the message to be printed is appended to «Epson Printer: «.
public class EpsonPrinter implements Printer < private static final Logger LOGGER = LoggerFactory.getLogger(EpsonPrinter.class); @Override public void print(String message) < LOGGER.info("Epson Printer : <>", message); > >
Step 4: Specialized Implementation of Printer for an HP Printer, in this case, the message to be printed is appended to «HP Printer: «.
public class HpPrinter implements Printer < private static final Logger LOGGER = LoggerFactory.getLogger(HpPrinter.class); @Override public void print(String message) < LOGGER.info("HP Printer : <>", message); > >
- when the actual implementation of the Printer class changes the delegation will still be operational
- the actual benefit is observed when there is more than one implementor and they share a delegation control.
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); >>
public class App < public static final String MESSAGE_TO_PRINT = "hello world"; /** * Program entry point * * @param args command line args */ 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); canonPrinterController.print(MESSAGE_TO_PRINT); epsonPrinterController.print(MESSAGE_TO_PRINT); > >
Pro Java
Еще один вид отношений, не поддерживаемый в Java напрямую, называется делегированием (delegation). Он занимает промежуточное положение между наследованием и композицией: экземпляр существующего класса включается в создаваемый класс (как при композиции), но в то же время все или некоторые методы встроенного объекта становятся доступными в новом классе (как при наследовании) . Очень часто такие виды отношений используются при построении графического интерфейса, например для реализации модели MVC библиотека Swing использует делегирование.
А сейчас рассмотрим на простом примере что же это за зверь такой – делегирование.
Например, класс SpaceShipControls имитирует модуль управления космическим кораблем. А Для построения космического корабля можно воспользоваться наследованием в классе SpaceShip.
Однако космический корабль не может рассматриваться как частный случай своего управляющего модуля — несмотря на то, что ему, к примеру, можно приказать двигаться вперед (forward()). Точнее сказать, что SpaceShip содержит SpaceShipControls, и в то же время все методы последнего предоставляются классом SpaceShip. Проблема решается при помощи делегирования:
Как видите, вызовы методов переадресуются встроенному объекту controls, а интерфейс остается таким же, как и при наследовании. С другой стороны, делегирование позволяет лучше управлять происходящим, потому что вы можете ограничиться небольшим подмножеством методов встроенного объекта.