SlideShare a Scribd company logo
Lecture 06 
Using Design Patterns
Agenda 
 Base Patterns 
– Gateway, Mapper, Layerd Supertype, Separated 
Interface, Registry, Value Object, Plugin, Service 
Stub, Record Set 
 From Problem to Patterns 
– Using design patterns
Using Design Patterns 
 Normally we don’t start with patterns 
– We start with problems to solve 
– From Problem to Pattern 
 Must have clear objectives for the design 
– The patterns will come as they are needed 
 Establish Design Principles 
– This applies to your application 
 Remember the separation of concern
From Problem to Pattern 
 How do I reuse common functionality of my 
objects? 
– Layer Supertype
Layer Supertype 
A type that acts as the supertype 
for all types in its layer 
 Super class that contains common functionality 
in a layer 
 How it works 
– Use this pattern when you 
have common features 
from all objects in a layer
Layer Supertype 
 When to use it 
– When you have common features from all objects in a 
layer 
 Example 
– Domain objects can 
have a common 
superclass for 
ID handling 
class DomainObject... 
private Long ID; 
public Long getID() 
{ 
return ID; 
} 
public void setID(Long ID) 
{ 
this.ID = ID; 
} 
public DomainObject(Long ID) 
{ 
this.ID = ID; 
}
From Problem to Pattern 
 How do I access an external service without 
becoming too dependant on it? 
– Gateway
Gateway 
An object that encapsulates access to an external 
system or resource 
 Wrap external APIs into an interface 
– API is usually for accessing some external resource 
• Examples: JDBC, JDom, financial software
Gateway 
 How It Works 
– Create a simple API and use it access the external 
API through a Gateway 
– All access is easily defined 
– Change in the resource does not require changes in 
the client software 
– Gateways should be simple – complex logic should 
not be in the clients of the Gateway 
– Gateways can be generated
Gateway 
 When to Use It 
– Gateway is useful when accessing external service 
– Can be applied with Service Stub (504) 
– Clear benefit is that is makes it easy to swap out one 
kind of resource for another
From Problem to Pattern 
 How do I avoid creating unwanted 
dependencies? 
–Separated Interface
Separated Interface 
Defines an interface in a separate 
package from its implementation 
 Decouples parts of a system 
– Controls the dependencies between packages 
– Implementation can easily be changed 
 How it works 
– Interface and implementation is placed in separate 
packages 
– Client uses the interface 
– Implementation can be determined at configuration 
time
Separated Interface 
 Layered System 
– Domain layer depends on Data Source layer 
– Data Source layer cannot access Domain layer 
Domain Layer 
Data Source Layer 
JDBC 
Code 
Concreate class 
RowCallBackHandler 
processRow(ResultSet rs) 
Interface 
RowCallBackHandler 
processRow(ResultSet rs) 
implements 
Code reading SQL 
Execution calls 
Separated interface
Separated Interface 
 Instantiating the implementation 
– User of the interface should not know the 
implementation 
– User of the interface creates the interface 
• The Arrray.sort developer creates Comparable 
• The Person developer implements Comparable 
 Solutions 
– Use a Factory and Plugin method 
– Use Dependency Injection
From Problem to Pattern 
 How do I test my client code using a service that 
I don’t have access to? 
– Service Stub
Service Stub 
Removes dependence upon problematic 
services during testing 
 Enterprise systems often need to access 
external system 
– Can be out of developers control
Service Stub 
 Service stub provides implementation for 
development and testing purposes 
– Runs locally and in-memory 
– Implements the same interface of the gateway used 
to access the real service 
 When to Use It 
– Service stub is useful when dependence on a 
particular service is hindering development or testing 
– Called “Mock Object” in the extreme programming 
world
From Problem to Pattern 
 How do I link to my implementation class using 
configuration 
– Plugin
Plugin 
Links classes during configuration 
rather than compilation 
 Use plugin to provide specific implantation 
– Plugins implement specific interface use by the client 
application code 
– Decision at configuration time or run time 
– Use factory to load in the plugin 
– For example: on plugin for test, another for production
Plugin 
 A caller obtains a Plugin implementation of a 
caller a plugin factory a plugin configuration 
getPlugin 
lookupPluginByType 
new 
a plugin 
separated interface 
 When to Use It 
– Use plugin when you have behavior that requires 
different implementations based on runtime 
environment
From Problem to Pattern 
 How can I keep common object available within 
the application 
– Registry
Registry 
A well-known object that other objects can use 
to find common objects and services 
 A registry is a global object 
 How It Works 
– Object that can easily be accessed at any time 
– Only one object available at any time 
– Provides services or information 
– Can have different scopes 
– Usually not mutable data 
– Example: System Settings, Loggers
Registry 
 In this implementation, only one instance running 
public class Registry 
{ 
private static Registry soleInstance = new Registry(); 
public static Registry getInstance() 
{ 
return soleInstance; 
 When to Use It 
– As a last resort 
} 
private Registry() 
{ 
} 
... 
} 
Registry registry = Registry.getInstance(); 
//registry = new Registry (); Does not work
From Problem to Pattern 
 I need to set up communication between two 
independent objects 
–Mapper
Mapper 
An object that sets up communiction between 
two independent objects 
 Create communication between two systems but 
you still need to make them independent
Mapper 
 How it Works 
– A Mapper is an insulating layer between subsystems 
– It controls the details of communication between them 
without either subsystem being aware of it 
– Mappers are fairly easy as they are well-defined 
– The tricky part is what system invokes them – third 
party system or make the Mapper an Observer 
 When to Use it 
– When you want to decouple different parts of a 
system
From Problem to Pattern 
 I need to define a simple immutable object that 
does not have any identity 
–Value Object
Value Object 
A small simple object, like money or date 
range, whose equality isn’t based on identity 
 Small and easily created objects that hold and 
represent some data 
 How it works 
– Not based on identity 
– Equality is based on comparing values of the object 
– Can be immutable (example is the Date class) 
 When to use it 
– When you’re basing equality on something other than 
identify
Value Object 
 Examples 
– Date, Money 
class Money... 
private long amount; 
private Currency currency; 
public Money(double amount, Currency currency) 
{ 
this.currency = currency; 
this.amount = Math.round(amount * centFactor()); 
} 
...
MailService
Mail Service 
 We are building an web application 
– One important service is sending messages in email 
– We need to access the e-mail service
Mail Service 
 During development we cannot have all features 
fully developed 
– We program in steps 
– Code, test, fix, code… 
– This also applies over releases 
– Maybe we have to use hacks in Version 1.0 
 Lifestyle: REFACTOR
Refactoring 
 Design, redesign, refactor 
– Make the design as complete as possible 
– But be prepared to change design as you code 
– Unit tests become very important 
 Code Smell 
– Think of your code as a baby: 
“If it smells, change it!”
Refactoring 
 Refactoring is the process of improving design in 
little steps at a time 
– Minimizes risks – calculated 
– Changes are controlled 
– Code can improve 
– Less likely to smell
The Danger 
 Technical Dept 
“I’ll fix it later” 
The four most dangerous and expensive words in 
programming
Conway’s Second Law 
 Technical Dept 
“There’s never enough time to do something right, but 
there’s always enough time to do it over”
Mail Service 
 We are building an web application 
– One important service is sending messages in email 
– We need to access the e-mail service
Mail Service 
 We decide to use JavaMail API 
– Problem is that this API is pretty low-level and 
complicated 
– Lots of “noise” – not good to have the domain 
developers worry about that 
What Design Pattern can we use here?
Mail Service Gateway 
 We build a simple gateway to handle mail 
– Domain developers don’t worry about the service 
– We can easily change to a different mail API
Gateway 
An object that encapsulates access to an external 
system or resource 
 Wrap external APIs into an interface 
– API is usually for accessing some external resource 
• Examples: JDBC, JDom, financial software
MailSender (1/2) 
 Class that sends the mail 
– Method send that takes care of sending the mail 
public class MailSender 
{ 
public void send(String from, String to, 
String subject, String body) 
{ 
String smtpServer = "mail.ru.is"; 
try 
{
MailSender (2/2) 
Properties props = System.getProperties(); 
props.put("mail.smtp.host", smtpServer); 
Session session = Session.getDefaultInstance(props, null); 
Message msg = new MimeMessage(session); 
msg.setFrom(new InternetAddress(from)); 
msg.setRecipients(Message.RecipientType.TO, 
InternetAddress.parse(to, false)); 
msg.setSubject(subject); 
msg.setText(body); 
msg.setSentDate(new Date()); 
Transport.send(msg); 
} 
catch (Exception ex) 
{ 
ex.printStackTrace(); 
} 
} 
}
MailSender 
 Name the problem with his class 
public class MailSender { 
public void send(String from, String to, String subject, String body) { 
String smtpServer = "mail.ru.is"; 
try { 
Properties props = System.getProperties(); 
props.put("mail.smtp.host", smtpServer); 
Session session = Session.getDefaultInstance(props, null); 
Message msg = new MimeMessage(session); 
msg.setFrom(new InternetAddress(from)); 
msg.setRecipients(Message.RecipientType.TO,InternetAddress.parse(to, false)); 
msg.setSubject(subject); 
msg.setText(body); 
msg.setSentDate(new Date()); 
Transport.send(msg); 
} catch (Exception ex) { ex.printStackTrace(); } 
} 
}
MailSender 
 Problem 
– Many parameters instead of an object 
– Mail server is hard-coded 
– Exception handling is bad 
– Programming to implementation 
public void send(String from, String to, 
String subject, String body) 
{ 
String smtpServer = ”smtp.ru.is"; 
try 
{ ... } 
catch (Exception ex) 
{ ex.printStackTrace();}}}
MailService 
 Interface for the domain developers 
– Program-to-interfaces Principle 
public interface MailService 
{ 
public void send(String from, String to, 
String subject, String body); 
} 
– So let MailSender implement this interface 
public class MailSender implements MailService 
{ 
public void send(String from, String to, 
String subject, String body) 
{ ...
Testing 
 Testing MailService and MainSender is easy 
public class TestMail 
{ 
public static void main(String[] args) 
{ 
MailService mail = new MailSender(); 
mail.send("andri@ru.is", // from 
"andri@ru.is", // to 
"Hallo", // subject 
"So does this stuff work"); // body 
} 
}
Testing 
TestMail: sending mail. 
Done. 
NOTE: mail.ru.is is not good for testing!
Testing 
 What is the problem with clients like this? 
public class TestMail 
{ 
public static void main(String[] args) 
{ 
MailService mail = new MailSender(); 
mail.send("andri@ru.is", // from 
"andri@ru.is", // to 
"Hallo", // subject 
"So does this stuff work"); // body 
} 
}
Improvements 
 Problem 
– MailSender implementation class is exposed to the 
domain layer 
 Solution 
– Use the Plugin Pattern 
– Create a factory that will read a configuration file 
and load the mail implementation class 
– Client will use the MailService interface
Plugin 
Links classes during configuration 
rather than compilation 
 Use plugin to provide specific implantation 
– Plugins implement specific interface use by the client 
application code 
– Decision at configuration time or run time 
– Use factory to load in the plugin 
• For example: one plugin for test, another for production
Factory with a Plugin 
 Create a MailFactory class 
– Loads mail.properties file 
– Creates the class specified in the properties file and 
returns interface MailService 
– Clients use MailService and are not exposed to 
particular implementation 
– It’s easy to change the properties file
Improvements 
 Problem 
– Can we make the loading of properties and class more 
generic? 
– Other factories might need this functionality also 
 Solution: 
– Create a Layer Supertype 
– MailFactory extends Factory
Layer Supertype 
A type that acts as the supertype 
for all types in its layer 
 Super class that contains common functionality 
in a layer 
 How it works 
– Use this pattern when you 
have common features 
from all objects in a layer
Layer Supertype 
A type that acts as the supertype 
for all types in its layer 
 Super class that contains common functionality 
in a layer 
 How it works 
– Use this pattern when you 
have common features 
from all objects in a layer
Plugin Pattern
Factory 
 Layer Supertype 
 Has two methods 
– loadPropertie and loadClass 
 Exception handling 
– Create a new exception class that we will use 
– FactoyException 
– Log the error
FactoryException 
 Extends Exception 
– Checked exception 
– Callers must catch this exception or explicitly throw it 
public class FactoryException extends Exception 
{ 
public FactoryException(String message) 
{ 
super(message); 
} 
public FactoryException(String message, Throwable cause) 
{ 
super(message, cause); 
} 
}
Factory 
public class Factory { 
Logger logger = Logger.getLogger(LogInfo.LOG_NAME); 
protected Properties loadProperties(String filename) 
throws FactoryException { 
Properties props = new Properties(); 
try 
{ 
props.load(new FileInputStream(new File(filename))); 
} 
catch (FileNotFoundException fnfex) 
{ 
String msg = "Factoy: File '" + filename + "' not found."; 
logger.severe(msg); 
throw new FactoryException(msg, fnfex); 
} 
... 
return props; 
}
Testing Fails 
 Exception is thrown and message is logged 
2.9.2007 16:49:34 is.ru.honn.rubook.factory.Factory loadClass 
SEVERE: Factoy: Class 'is.ru.honn.rubook.mail.MailServiceStubx' not found.
Testing Fails 
 Problem 
– MailService implementation classes have to 
handle FactoryException or pass it on 
– Do we want clients to worry about some factory? 
 Solution 
– One solution is to catch FactoryException and 
throw unchecked MailService exception
MailFactory 
public class MailFactory extends Factory 
{ 
public MailService getMailService() 
{ 
MailService service; 
try 
{ 
service = (MailService)loadClass( 
loadProperties("mail.properties"). 
getProperty("mail.service.class")); 
} 
catch(FactoryException fex) 
{ 
throw new MailServiceException ("Unable to send e-mail", fex); 
} 
return service; 
} 
}
MailServiceException 
 Extends RuntimeException 
– Unchecked exception 
– Callers decide if they want to catch it 
public class MailServiceException extends RuntimeException 
{ 
public MailServiceException(String message) 
{ 
super(message); 
} 
public MailServiceException(String message, Throwable cause) 
{ 
super(message, cause); 
} 
}
Testing 
 Using the MailFactory class 
– We can catch the MailServiceException or ignore it 
– Notice we have not only abstracted the Mail API but 
also the exception handling 
public class TestMail 
{ 
public static void main(String[] args) 
{ 
MailFactory mf = new MailFactory(); 
MailService mail = mf.getMailService(); 
mail.send("andri@ru.is", "andri@ru.is", "Hello", "Hello"); 
} 
}
Improvements 
 Problem 
– Exception handling in our original MailSender is bad 
 Solution 
– Use the MailServiceException 
public void send(MailMessage message) 
{ 
try { ... } 
catch (Exception ex) 
{ 
String msg = "Sending mail failed: " + ex.getMessage(); 
logger.severe(msg); 
throw new MailServiceException(msg, ex); 
} 
SEVERE: Sending mail failed: Unknown SMTP host: mail.ru.is
Improvements 
 Problem 
– What if we don’t have access to the SMTP server 
at this time? 
 Solution 
– Use a Service Stub 
– Create the class MailServiceStub that will simply log out 
the mail sent 
– Could also write in file
Service Stub 
Removes dependence upon problematic 
services during testing 
 Enterprise systems often need to access 
external system 
– Can be out of developers control
MailServiceStub 
public class MailServiceStub implements MailService 
{ 
Logger logger = Logger.getLogger(LogInfo.LOG_NAME); 
public void send(String from, String to, 
String subject, String body) 
{ 
logger.info("Sending mail from '" + from + "' to '" + to + 
"' Subject: '" + subject); 
} 
} 
2.9.2007 16:36:08 is.ru.honn.rubook.mail.MailServiceStub send 
INFO: Sending mail from 'andri@ru.is' to 'andri@ru.is' Subject: 'Hello 
mail.properties 
mail.service.class=is.ru.honn.rubook.mail.MailServiceStub
Improvements 
 Problem 
– What if we need to add new parameter? 
public interface MailService { 
public void send(String from, String to, 
 Solution 
String subject, String body); 
– Use an object to group parameters 
– Easy to change without changing the interface 
} 
public interface MailService 
{ 
public void send(MailMessage message); 
}
MailMessage 
 Typical Data Transfer Object 
public class MailMessage { 
private String from; 
private String to; 
private String subject; 
private String body; 
public MailMessage(String from, String to, 
String subject, String body) 
{ 
this.from = from; 
this.to = to; 
this.subject = subject; 
this.body = body; 
} 
public String getFrom() { return from; } 
public void setFrom(String from) { this.from = from; } 
...
Improvements 
 Problem 
– The mail server in MailSender is still hardcoded 
 Solution 
– Place in the configuration file 
– Let the factory inject the name into the 
Mail Service 
public interface MailService 
{ 
public void setMailServer(String mailServer); 
public void send(MailMessage message); 
}
Injecting the Mail Server Name
New MailFactoy 
 getMailService injects the name into the service 
public class MailFactory extends Factory 
{ 
public MailService getMailService() 
{ 
... 
loadProperties("mail.properties"); 
service = (MailService)loadClass(getProperties(). 
getProperty("mail.service.class")); 
service.setMailServer(getProperties(). 
getProperty("mail.server")); // injection 
return service; 
} 
} 
mail.service.class=is.ru.honn.rubook.mail.MailSender 
mail.server=mail.ru.is
Improvements 
 Problem 
– loadProperties loads the file each time used 
 Solution 
– Load once then use 
public class Factory 
{ 
private Properties properties = new Properties(); 
protected Properties loadProperties(String filename) throws FactoryException 
{ ... 
return properties; 
} 
public Properties getProperties() 
{ 
return properties; 
} ...
Improvements 
 Problem 
– All mail server implementations must store server name 
and set function 
– Common functionality in multiple classes 
 Solution 
– Create a Layered Supertype 
– Take care of the common functionality 
– Make the send method abstract
AbstractMailService 
 Implements MailService 
– Provides handling of the mail server property 
public abstract class AbstractMailService implements MailService 
{ 
protected String mailServer; 
// this is used by the factory to inject 
public void setMailServer(String mailServer) 
{ 
this.mailServer = mailServer; 
} 
public String getMailServer() 
{ 
return mailServer; 
} 
}
MailSender 
 Extends AbstractMailService 
– Does not have to implement the MailServer interface 
– Can use the getMailServer method 
public class MailSender extends AbstractMailService 
{ 
public void send(MailMessage message) 
{ 
try 
{ 
Properties props = System.getProperties(); 
props.put("mail.smtp.host", getMailServer()); 
...
Summary 
 Base Patterns 
• Gateway, Mapper, Layerd Supertype, Separated Interface, Registry, 
Value Object, Plugin, Service Stub, Record Set 
 We start with problems to solve 
– Then we find the patterns to use 
– Must have clear objectives for the design 
 Beware of code smell 
 Refactoring is the process of improving design in 
little steps at a time 
 Example case study 
– Mail service with a configurable factory

More Related Content

L06 Using Design Patterns

  • 1. Lecture 06 Using Design Patterns
  • 2. Agenda  Base Patterns – Gateway, Mapper, Layerd Supertype, Separated Interface, Registry, Value Object, Plugin, Service Stub, Record Set  From Problem to Patterns – Using design patterns
  • 3. Using Design Patterns  Normally we don’t start with patterns – We start with problems to solve – From Problem to Pattern  Must have clear objectives for the design – The patterns will come as they are needed  Establish Design Principles – This applies to your application  Remember the separation of concern
  • 4. From Problem to Pattern  How do I reuse common functionality of my objects? – Layer Supertype
  • 5. Layer Supertype A type that acts as the supertype for all types in its layer  Super class that contains common functionality in a layer  How it works – Use this pattern when you have common features from all objects in a layer
  • 6. Layer Supertype  When to use it – When you have common features from all objects in a layer  Example – Domain objects can have a common superclass for ID handling class DomainObject... private Long ID; public Long getID() { return ID; } public void setID(Long ID) { this.ID = ID; } public DomainObject(Long ID) { this.ID = ID; }
  • 7. From Problem to Pattern  How do I access an external service without becoming too dependant on it? – Gateway
  • 8. Gateway An object that encapsulates access to an external system or resource  Wrap external APIs into an interface – API is usually for accessing some external resource • Examples: JDBC, JDom, financial software
  • 9. Gateway  How It Works – Create a simple API and use it access the external API through a Gateway – All access is easily defined – Change in the resource does not require changes in the client software – Gateways should be simple – complex logic should not be in the clients of the Gateway – Gateways can be generated
  • 10. Gateway  When to Use It – Gateway is useful when accessing external service – Can be applied with Service Stub (504) – Clear benefit is that is makes it easy to swap out one kind of resource for another
  • 11. From Problem to Pattern  How do I avoid creating unwanted dependencies? –Separated Interface
  • 12. Separated Interface Defines an interface in a separate package from its implementation  Decouples parts of a system – Controls the dependencies between packages – Implementation can easily be changed  How it works – Interface and implementation is placed in separate packages – Client uses the interface – Implementation can be determined at configuration time
  • 13. Separated Interface  Layered System – Domain layer depends on Data Source layer – Data Source layer cannot access Domain layer Domain Layer Data Source Layer JDBC Code Concreate class RowCallBackHandler processRow(ResultSet rs) Interface RowCallBackHandler processRow(ResultSet rs) implements Code reading SQL Execution calls Separated interface
  • 14. Separated Interface  Instantiating the implementation – User of the interface should not know the implementation – User of the interface creates the interface • The Arrray.sort developer creates Comparable • The Person developer implements Comparable  Solutions – Use a Factory and Plugin method – Use Dependency Injection
  • 15. From Problem to Pattern  How do I test my client code using a service that I don’t have access to? – Service Stub
  • 16. Service Stub Removes dependence upon problematic services during testing  Enterprise systems often need to access external system – Can be out of developers control
  • 17. Service Stub  Service stub provides implementation for development and testing purposes – Runs locally and in-memory – Implements the same interface of the gateway used to access the real service  When to Use It – Service stub is useful when dependence on a particular service is hindering development or testing – Called “Mock Object” in the extreme programming world
  • 18. From Problem to Pattern  How do I link to my implementation class using configuration – Plugin
  • 19. Plugin Links classes during configuration rather than compilation  Use plugin to provide specific implantation – Plugins implement specific interface use by the client application code – Decision at configuration time or run time – Use factory to load in the plugin – For example: on plugin for test, another for production
  • 20. Plugin  A caller obtains a Plugin implementation of a caller a plugin factory a plugin configuration getPlugin lookupPluginByType new a plugin separated interface  When to Use It – Use plugin when you have behavior that requires different implementations based on runtime environment
  • 21. From Problem to Pattern  How can I keep common object available within the application – Registry
  • 22. Registry A well-known object that other objects can use to find common objects and services  A registry is a global object  How It Works – Object that can easily be accessed at any time – Only one object available at any time – Provides services or information – Can have different scopes – Usually not mutable data – Example: System Settings, Loggers
  • 23. Registry  In this implementation, only one instance running public class Registry { private static Registry soleInstance = new Registry(); public static Registry getInstance() { return soleInstance;  When to Use It – As a last resort } private Registry() { } ... } Registry registry = Registry.getInstance(); //registry = new Registry (); Does not work
  • 24. From Problem to Pattern  I need to set up communication between two independent objects –Mapper
  • 25. Mapper An object that sets up communiction between two independent objects  Create communication between two systems but you still need to make them independent
  • 26. Mapper  How it Works – A Mapper is an insulating layer between subsystems – It controls the details of communication between them without either subsystem being aware of it – Mappers are fairly easy as they are well-defined – The tricky part is what system invokes them – third party system or make the Mapper an Observer  When to Use it – When you want to decouple different parts of a system
  • 27. From Problem to Pattern  I need to define a simple immutable object that does not have any identity –Value Object
  • 28. Value Object A small simple object, like money or date range, whose equality isn’t based on identity  Small and easily created objects that hold and represent some data  How it works – Not based on identity – Equality is based on comparing values of the object – Can be immutable (example is the Date class)  When to use it – When you’re basing equality on something other than identify
  • 29. Value Object  Examples – Date, Money class Money... private long amount; private Currency currency; public Money(double amount, Currency currency) { this.currency = currency; this.amount = Math.round(amount * centFactor()); } ...
  • 31. Mail Service  We are building an web application – One important service is sending messages in email – We need to access the e-mail service
  • 32. Mail Service  During development we cannot have all features fully developed – We program in steps – Code, test, fix, code… – This also applies over releases – Maybe we have to use hacks in Version 1.0  Lifestyle: REFACTOR
  • 33. Refactoring  Design, redesign, refactor – Make the design as complete as possible – But be prepared to change design as you code – Unit tests become very important  Code Smell – Think of your code as a baby: “If it smells, change it!”
  • 34. Refactoring  Refactoring is the process of improving design in little steps at a time – Minimizes risks – calculated – Changes are controlled – Code can improve – Less likely to smell
  • 35. The Danger  Technical Dept “I’ll fix it later” The four most dangerous and expensive words in programming
  • 36. Conway’s Second Law  Technical Dept “There’s never enough time to do something right, but there’s always enough time to do it over”
  • 37. Mail Service  We are building an web application – One important service is sending messages in email – We need to access the e-mail service
  • 38. Mail Service  We decide to use JavaMail API – Problem is that this API is pretty low-level and complicated – Lots of “noise” – not good to have the domain developers worry about that What Design Pattern can we use here?
  • 39. Mail Service Gateway  We build a simple gateway to handle mail – Domain developers don’t worry about the service – We can easily change to a different mail API
  • 40. Gateway An object that encapsulates access to an external system or resource  Wrap external APIs into an interface – API is usually for accessing some external resource • Examples: JDBC, JDom, financial software
  • 41. MailSender (1/2)  Class that sends the mail – Method send that takes care of sending the mail public class MailSender { public void send(String from, String to, String subject, String body) { String smtpServer = "mail.ru.is"; try {
  • 42. MailSender (2/2) Properties props = System.getProperties(); props.put("mail.smtp.host", smtpServer); Session session = Session.getDefaultInstance(props, null); Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress(from)); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false)); msg.setSubject(subject); msg.setText(body); msg.setSentDate(new Date()); Transport.send(msg); } catch (Exception ex) { ex.printStackTrace(); } } }
  • 43. MailSender  Name the problem with his class public class MailSender { public void send(String from, String to, String subject, String body) { String smtpServer = "mail.ru.is"; try { Properties props = System.getProperties(); props.put("mail.smtp.host", smtpServer); Session session = Session.getDefaultInstance(props, null); Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress(from)); msg.setRecipients(Message.RecipientType.TO,InternetAddress.parse(to, false)); msg.setSubject(subject); msg.setText(body); msg.setSentDate(new Date()); Transport.send(msg); } catch (Exception ex) { ex.printStackTrace(); } } }
  • 44. MailSender  Problem – Many parameters instead of an object – Mail server is hard-coded – Exception handling is bad – Programming to implementation public void send(String from, String to, String subject, String body) { String smtpServer = ”smtp.ru.is"; try { ... } catch (Exception ex) { ex.printStackTrace();}}}
  • 45. MailService  Interface for the domain developers – Program-to-interfaces Principle public interface MailService { public void send(String from, String to, String subject, String body); } – So let MailSender implement this interface public class MailSender implements MailService { public void send(String from, String to, String subject, String body) { ...
  • 46. Testing  Testing MailService and MainSender is easy public class TestMail { public static void main(String[] args) { MailService mail = new MailSender(); mail.send("andri@ru.is", // from "andri@ru.is", // to "Hallo", // subject "So does this stuff work"); // body } }
  • 47. Testing TestMail: sending mail. Done. NOTE: mail.ru.is is not good for testing!
  • 48. Testing  What is the problem with clients like this? public class TestMail { public static void main(String[] args) { MailService mail = new MailSender(); mail.send("andri@ru.is", // from "andri@ru.is", // to "Hallo", // subject "So does this stuff work"); // body } }
  • 49. Improvements  Problem – MailSender implementation class is exposed to the domain layer  Solution – Use the Plugin Pattern – Create a factory that will read a configuration file and load the mail implementation class – Client will use the MailService interface
  • 50. Plugin Links classes during configuration rather than compilation  Use plugin to provide specific implantation – Plugins implement specific interface use by the client application code – Decision at configuration time or run time – Use factory to load in the plugin • For example: one plugin for test, another for production
  • 51. Factory with a Plugin  Create a MailFactory class – Loads mail.properties file – Creates the class specified in the properties file and returns interface MailService – Clients use MailService and are not exposed to particular implementation – It’s easy to change the properties file
  • 52. Improvements  Problem – Can we make the loading of properties and class more generic? – Other factories might need this functionality also  Solution: – Create a Layer Supertype – MailFactory extends Factory
  • 53. Layer Supertype A type that acts as the supertype for all types in its layer  Super class that contains common functionality in a layer  How it works – Use this pattern when you have common features from all objects in a layer
  • 54. Layer Supertype A type that acts as the supertype for all types in its layer  Super class that contains common functionality in a layer  How it works – Use this pattern when you have common features from all objects in a layer
  • 56. Factory  Layer Supertype  Has two methods – loadPropertie and loadClass  Exception handling – Create a new exception class that we will use – FactoyException – Log the error
  • 57. FactoryException  Extends Exception – Checked exception – Callers must catch this exception or explicitly throw it public class FactoryException extends Exception { public FactoryException(String message) { super(message); } public FactoryException(String message, Throwable cause) { super(message, cause); } }
  • 58. Factory public class Factory { Logger logger = Logger.getLogger(LogInfo.LOG_NAME); protected Properties loadProperties(String filename) throws FactoryException { Properties props = new Properties(); try { props.load(new FileInputStream(new File(filename))); } catch (FileNotFoundException fnfex) { String msg = "Factoy: File '" + filename + "' not found."; logger.severe(msg); throw new FactoryException(msg, fnfex); } ... return props; }
  • 59. Testing Fails  Exception is thrown and message is logged 2.9.2007 16:49:34 is.ru.honn.rubook.factory.Factory loadClass SEVERE: Factoy: Class 'is.ru.honn.rubook.mail.MailServiceStubx' not found.
  • 60. Testing Fails  Problem – MailService implementation classes have to handle FactoryException or pass it on – Do we want clients to worry about some factory?  Solution – One solution is to catch FactoryException and throw unchecked MailService exception
  • 61. MailFactory public class MailFactory extends Factory { public MailService getMailService() { MailService service; try { service = (MailService)loadClass( loadProperties("mail.properties"). getProperty("mail.service.class")); } catch(FactoryException fex) { throw new MailServiceException ("Unable to send e-mail", fex); } return service; } }
  • 62. MailServiceException  Extends RuntimeException – Unchecked exception – Callers decide if they want to catch it public class MailServiceException extends RuntimeException { public MailServiceException(String message) { super(message); } public MailServiceException(String message, Throwable cause) { super(message, cause); } }
  • 63. Testing  Using the MailFactory class – We can catch the MailServiceException or ignore it – Notice we have not only abstracted the Mail API but also the exception handling public class TestMail { public static void main(String[] args) { MailFactory mf = new MailFactory(); MailService mail = mf.getMailService(); mail.send("andri@ru.is", "andri@ru.is", "Hello", "Hello"); } }
  • 64. Improvements  Problem – Exception handling in our original MailSender is bad  Solution – Use the MailServiceException public void send(MailMessage message) { try { ... } catch (Exception ex) { String msg = "Sending mail failed: " + ex.getMessage(); logger.severe(msg); throw new MailServiceException(msg, ex); } SEVERE: Sending mail failed: Unknown SMTP host: mail.ru.is
  • 65. Improvements  Problem – What if we don’t have access to the SMTP server at this time?  Solution – Use a Service Stub – Create the class MailServiceStub that will simply log out the mail sent – Could also write in file
  • 66. Service Stub Removes dependence upon problematic services during testing  Enterprise systems often need to access external system – Can be out of developers control
  • 67. MailServiceStub public class MailServiceStub implements MailService { Logger logger = Logger.getLogger(LogInfo.LOG_NAME); public void send(String from, String to, String subject, String body) { logger.info("Sending mail from '" + from + "' to '" + to + "' Subject: '" + subject); } } 2.9.2007 16:36:08 is.ru.honn.rubook.mail.MailServiceStub send INFO: Sending mail from 'andri@ru.is' to 'andri@ru.is' Subject: 'Hello mail.properties mail.service.class=is.ru.honn.rubook.mail.MailServiceStub
  • 68. Improvements  Problem – What if we need to add new parameter? public interface MailService { public void send(String from, String to,  Solution String subject, String body); – Use an object to group parameters – Easy to change without changing the interface } public interface MailService { public void send(MailMessage message); }
  • 69. MailMessage  Typical Data Transfer Object public class MailMessage { private String from; private String to; private String subject; private String body; public MailMessage(String from, String to, String subject, String body) { this.from = from; this.to = to; this.subject = subject; this.body = body; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } ...
  • 70. Improvements  Problem – The mail server in MailSender is still hardcoded  Solution – Place in the configuration file – Let the factory inject the name into the Mail Service public interface MailService { public void setMailServer(String mailServer); public void send(MailMessage message); }
  • 71. Injecting the Mail Server Name
  • 72. New MailFactoy  getMailService injects the name into the service public class MailFactory extends Factory { public MailService getMailService() { ... loadProperties("mail.properties"); service = (MailService)loadClass(getProperties(). getProperty("mail.service.class")); service.setMailServer(getProperties(). getProperty("mail.server")); // injection return service; } } mail.service.class=is.ru.honn.rubook.mail.MailSender mail.server=mail.ru.is
  • 73. Improvements  Problem – loadProperties loads the file each time used  Solution – Load once then use public class Factory { private Properties properties = new Properties(); protected Properties loadProperties(String filename) throws FactoryException { ... return properties; } public Properties getProperties() { return properties; } ...
  • 74. Improvements  Problem – All mail server implementations must store server name and set function – Common functionality in multiple classes  Solution – Create a Layered Supertype – Take care of the common functionality – Make the send method abstract
  • 75. AbstractMailService  Implements MailService – Provides handling of the mail server property public abstract class AbstractMailService implements MailService { protected String mailServer; // this is used by the factory to inject public void setMailServer(String mailServer) { this.mailServer = mailServer; } public String getMailServer() { return mailServer; } }
  • 76. MailSender  Extends AbstractMailService – Does not have to implement the MailServer interface – Can use the getMailServer method public class MailSender extends AbstractMailService { public void send(MailMessage message) { try { Properties props = System.getProperties(); props.put("mail.smtp.host", getMailServer()); ...
  • 77. Summary  Base Patterns • Gateway, Mapper, Layerd Supertype, Separated Interface, Registry, Value Object, Plugin, Service Stub, Record Set  We start with problems to solve – Then we find the patterns to use – Must have clear objectives for the design  Beware of code smell  Refactoring is the process of improving design in little steps at a time  Example case study – Mail service with a configurable factory