l06 using design patterns
DESCRIPTION
Hönnunarmunstur eru aðferðir við að leysa algeng vandamál. En notkun þeirra felst í að takast á við verkefni sem þarf að leysa. Fyrst koma verkefnin og svo finnum við hvaða munstur hentar miðað við þær forsendur sem við höfum. Oft þegar verið er að vinna að lausnum þá er alls ekki hægt að gera allan hugbúnaðinn í einu, heldur þarf að "hakka" suma hluti meðan unnið er í öðru. Til þess að lenda ekki í technical dept þarf að vera með stöðugt refactoring. Í þessum fyrirlestri skoðum við vandamál og rifjum upp grunnmunstrin (base patterns) sem við kynntumst í L05 Design Patterns. Þá skoðum við hvernig við leysum tengingu við póstþjón.TRANSCRIPT
![Page 1: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/1.jpg)
Lecture 06Using Design Patterns
![Page 2: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/2.jpg)
Agenda Base Patterns
– Gateway, Mapper, Layerd Supertype, Separated Interface, Registry, Value Object, Plugin, Service Stub, Record Set
From Problem to Patterns– Using design patterns
![Page 3: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/3.jpg)
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
![Page 4: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/4.jpg)
From Problem to Pattern How do I reuse common functionality of
my objects?–Layer Supertype
![Page 5: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/5.jpg)
Layer SupertypeA 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
![Page 6: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/6.jpg)
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; }
![Page 7: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/7.jpg)
From Problem to Pattern How do I access an external service
without becoming too dependant on it?–Gateway
![Page 8: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/8.jpg)
GatewayAn 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
![Page 9: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/9.jpg)
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
![Page 10: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/10.jpg)
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
![Page 11: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/11.jpg)
From Problem to Pattern How do I avoid creating unwanted
dependencies?–Separated Interface
![Page 12: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/12.jpg)
Separated InterfaceDefines 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
![Page 13: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/13.jpg)
Separated Interface Layered System
– Domain layer depends on Data Source layer– Data Source layer cannot access Domain layer
Data Source Layer
Domain Layer
JDBCCode
InterfaceRowCallBackHandler
processRow(ResultSet rs)
Concreate classRowCallBackHandler
processRow(ResultSet rs)
implements
Code reading SQL
Execution calls
Separated interface
![Page 14: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/14.jpg)
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
![Page 15: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/15.jpg)
From Problem to Pattern How do I test my client code using a
service that I don’t have access to?–Service Stub
![Page 16: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/16.jpg)
Service StubRemoves dependence upon problematic
services during testing Enterprise systems often need to access
external system– Can be out of developers control
![Page 17: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/17.jpg)
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
![Page 18: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/18.jpg)
From Problem to Pattern How do I link to my implementation class
using configuration–Plugin
![Page 19: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/19.jpg)
PluginLinks 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
![Page 20: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/20.jpg)
Plugin
caller a plugin factory a plugin configuration
getPlugin
lookupPluginByType
newa plugin
A caller obtains a Plugin implementation of a separated interface
When to Use It– Use plugin when you have behavior that
requires different implementations based on runtime environment
![Page 21: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/21.jpg)
From Problem to Pattern How can I keep common object available
within the application–Registry
![Page 22: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/22.jpg)
RegistryA 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
![Page 23: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/23.jpg)
Registry In this implementation, only one instance running
When to Use It– As a last resort
public class Registry{ private static Registry soleInstance = new Registry();
public static Registry getInstance() { return soleInstance; }
private Registry() { } ...}
Registry registry = Registry.getInstance();//registry = new Registry (); Does not work
![Page 24: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/24.jpg)
From Problem to Pattern I need to set up communication between
two independent objects–Mapper
![Page 25: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/25.jpg)
MapperAn object that sets up communiction
between two independent objects Create communication between two
systems but you still need to make them independent
![Page 26: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/26.jpg)
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
![Page 27: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/27.jpg)
From Problem to Pattern I need to define a simple immutable object
that does not have any identity –Value Object
![Page 28: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/28.jpg)
Value ObjectA 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
![Page 29: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/29.jpg)
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()); } ...
![Page 30: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/30.jpg)
MailService
![Page 31: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/31.jpg)
Mail Service We are building an web application
– One important service is sending messages in email
– We need to access the e-mail service
![Page 32: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/32.jpg)
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
![Page 33: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/33.jpg)
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!”
![Page 34: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/34.jpg)
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
![Page 35: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/35.jpg)
The Danger Technical Dept
“I’ll fix it later”
The four most dangerous and expensive words in programming
![Page 36: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/36.jpg)
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”
![Page 37: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/37.jpg)
Mail Service We are building an web application
– One important service is sending messages in email
– We need to access the e-mail service
![Page 38: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/38.jpg)
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?
![Page 39: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/39.jpg)
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
![Page 40: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/40.jpg)
GatewayAn 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
![Page 41: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/41.jpg)
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 {
![Page 42: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/42.jpg)
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(); } }}
![Page 43: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/43.jpg)
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(); } }}
![Page 44: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/44.jpg)
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();}}}
![Page 45: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/45.jpg)
MailService Interface for the domain developers
– Program-to-interfaces Principle
– So let MailSender implement this interface
public interface MailService{ public void send(String from, String to, String subject, String body);}
public class MailSender implements MailService{ public void send(String from, String to, String subject, String body) { ...
![Page 46: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/46.jpg)
Testing Testing MailService and MainSender is
easypublic class TestMail{ public static void main(String[] args) { MailService mail = new MailSender(); mail.send("[email protected]", // from "[email protected]", // to "Hallo", // subject "So does this stuff work"); // body }}
![Page 47: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/47.jpg)
TestingTestMail: sending mail.Done.
NOTE: mail.ru.is is not good for testing!
![Page 48: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/48.jpg)
Testing What is the problem with clients like this?
public class TestMail{ public static void main(String[] args) { MailService mail = new MailSender(); mail.send("[email protected]", // from "[email protected]", // to "Hallo", // subject "So does this stuff work"); // body }}
![Page 49: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/49.jpg)
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
![Page 50: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/50.jpg)
PluginLinks 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
![Page 51: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/51.jpg)
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
![Page 52: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/52.jpg)
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
![Page 53: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/53.jpg)
Layer SupertypeA 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
![Page 54: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/54.jpg)
Layer SupertypeA 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
![Page 55: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/55.jpg)
Plugin Pattern
![Page 56: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/56.jpg)
Factory Layer Supertype Has two methods
– loadPropertie and loadClass Exception handling
– Create a new exception class that we will use– FactoyException– Log the error
![Page 57: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/57.jpg)
FactoryException Extends Exception
– Checked exception– Callers must catch this exception or explicitly
throw itpublic class FactoryException extends Exception{ public FactoryException(String message) { super(message); }
public FactoryException(String message, Throwable cause) { super(message, cause); }}
![Page 58: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/58.jpg)
Factorypublic 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; }
![Page 59: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/59.jpg)
Testing Fails Exception is thrown and message is
logged2.9.2007 16:49:34 is.ru.honn.rubook.factory.Factory loadClassSEVERE: Factoy: Class 'is.ru.honn.rubook.mail.MailServiceStubx' not found.
![Page 60: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/60.jpg)
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
![Page 61: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/61.jpg)
MailFactorypublic 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; }}
![Page 62: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/62.jpg)
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); }}
![Page 63: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/63.jpg)
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("[email protected]", "[email protected]", "Hello", "Hello"); }}
![Page 64: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/64.jpg)
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
![Page 65: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/65.jpg)
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
![Page 66: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/66.jpg)
Service StubRemoves dependence upon problematic
services during testing Enterprise systems often need to access
external system– Can be out of developers control
![Page 67: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/67.jpg)
MailServiceStubpublic 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 sendINFO: Sending mail from '[email protected]' to '[email protected]' Subject: 'Hello
mail.service.class=is.ru.honn.rubook.mail.MailServiceStub
mail.properties
![Page 68: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/68.jpg)
Improvements Problem
– What if we need to add new parameter?
Solution– Use an object to group parameters– Easy to change without changing the interface
public interface MailService { public void send(String from, String to, String subject, String body);}
public interface MailService{ public void send(MailMessage message);}
![Page 69: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/69.jpg)
MailMessage Typical Data Transfer Objectpublic 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; }...
![Page 70: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/70.jpg)
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 Servicepublic interface MailService{ public void setMailServer(String mailServer); public void send(MailMessage message);}
![Page 71: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/71.jpg)
Injecting the Mail Server Name
![Page 72: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/72.jpg)
New MailFactoy getMailService injects the name into the
servicepublic 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.MailSendermail.server=mail.ru.is
![Page 73: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/73.jpg)
Improvements Problem
– loadProperties loads the file each time used Solution
– Load once then usepublic class Factory{ private Properties properties = new Properties();
protected Properties loadProperties(String filename) throws FactoryException { ... return properties; } public Properties getProperties() { return properties; } ...
![Page 74: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/74.jpg)
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
![Page 75: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/75.jpg)
AbstractMailService Implements MailService
– Provides handling of the mail server propertypublic 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; }}
![Page 76: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/76.jpg)
MailSender Extends AbstractMailService
– Does not have to implement the MailServer interface
– Can use the getMailServer methodpublic class MailSender extends AbstractMailService{ public void send(MailMessage message) { try { Properties props = System.getProperties(); props.put("mail.smtp.host", getMailServer()); ...
![Page 77: L06 Using Design Patterns](https://reader034.vdocuments.net/reader034/viewer/2022042518/5457c97ab1af9f37608b5189/html5/thumbnails/77.jpg)
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