+ All Categories
Home > Technology > L04 base patterns

L04 base patterns

Date post: 11-Jan-2015
Category:
Upload: olafur-andri-ragnarsson
View: 430 times
Download: 2 times
Share this document with a friend
Description:
In this lecture we look at the patterns in chapter 18 in the textbook (Patterns of Enterprise Application Architecture). The lecture is in two parts. First we go through each of the patterns and explain each. Then in the second part we look at a problem we have to solve and try to get the patterns to show themselves at the time they are needed.
88
Lecture 04 Base Patterns
Transcript
Page 1: L04 base patterns

Lecture 04Base Patterns

Page 2: L04 base 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

Page 3: L04 base patterns

Reading Fowler 18

Page 4: L04 base patterns

Gateway (466)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

Page 5: L04 base patterns

Gateway (466) 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 6: L04 base patterns

Gateway (466) 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 7: L04 base patterns

Mapper (473)An object that sets up communiction

between two independent objects Create communication between two

systems but you still need to make them independent

Page 8: L04 base patterns

Mapper (473) 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 9: L04 base patterns

Layer Supertype (475)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

Page 10: L04 base patterns

Layer Supertype (475) 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 11: L04 base patterns

Example: Drawing system Shape class revisited

– All objects in the drawing layer must have an origin (x and y) and implement Drawable

public abstract class Shape implements Drawable{ protected int x,y;}

Page 12: L04 base patterns

Separated Interface (476)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

Page 13: L04 base patterns

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: L04 base patterns

Separated Interface (476) Implementation is placed in a separate

packageDevelopers of the client package are responsible for the interface

Page 15: L04 base patterns

Separated Interface (476) Placing the Separated

Interfaced in a third package

When to use it– When you need to break a dependency

between two parts of a system

Page 16: L04 base patterns

Separated Interface (476)

Page 17: L04 base patterns

Separated Interface (476) Instantiating the implementation

– User of the interface should not know the implementation

Solutions– Use a Factory and Plugin method– Use Dependency Injection

Page 18: L04 base patterns

Separated Interface (476)public interface FeedHandler{ public void processObject (FeedEntry entry);}

public class ReaderClient implements FeedHandler{ ... public ReaderClient() { FeedReader reader = ReaderFactory.getFeedReader(); reader.setFeedHandler(this); reader.read("http://rss.news.yahoo.com/rss/tech"); }

public void processObject(FeedEntry entry) { System.out.println(entry); }}

Callback

Page 19: L04 base patterns

Registry (480)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

Page 20: L04 base patterns

Singleton Registry (480) 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 21: L04 base patterns

Value Object (486)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

Page 22: L04 base patterns

Value Object (486) 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 23: L04 base patterns

Value Object Example: DateGregorianCalendar cal = new GregorianCalendar();

cal.set(1865, Calendar.APRIL, 14);Date d1 = cal.getTime();cal.set(1963, Calendar.NOVEMBER, 22);Date d2 = cal.getTime();

System.out.println(d1.equals(d2));

cal.set(1756, Calendar.JANUARY, 27);Date d3 = cal.getTime();Date d4 = cal.getTime();

System.out.println(d3.equals(d4));falsetrue

Page 24: L04 base patterns

Plugin (499)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

Page 25: L04 base patterns

Plugin (499)

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 26: L04 base patterns

Plugin (499) ReaderClient uses ReaderFactory to get an

interface to FeedReader

reader.properties define the name of the actual implementation class

ReaderClient ReaderFactory reader.properties

getFeedReader

props.getProperty("reader")

newFeedReader

Page 27: L04 base patterns

Plugin (499)public ReaderClient(){ FeedReader reader = ReaderFactory.getFeedReader(); ...} public class ReaderFactory

{ public static FeedReader getFeedReader() { ... try { props.load(new FileInputStream(new File("reader.properties"))); instanceClass = Class.forName(props.getProperty("reader")); reader = (FeedReader)instanceClass.newInstance(); } ... return reader; }} reader=RssFeedReader

Page 28: L04 base patterns

Service Stub (504)Removes dependence upon problematic

services during testing Enterprise systems often need to access

external system– Can be out of developers control

Page 29: L04 base patterns

Service Stub (504) 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 30: L04 base patterns

Service Stub Examplespublic class ReaderStub extends AbstractFeedReader{ public void read(String url) { feedHandler.processEntry(new FeedEntry("title1", "Bla bla bla")); feedHandler.processEntry(new FeedEntry("title2", "Bla bla bla")); feedHandler.processEntry(new FeedEntry("title3", "Bla bla bla")); }}

title1Bla bla blatitle2Bla bla blatitle3Bla bla bla

reader=ReaderStub

reader.properties

Page 31: L04 base patterns

Record Set (508)An in-memory representation of tabular data

Allows you to access database data from other objects– Scroll through a list of data

Page 32: L04 base patterns

Record Set (508) How it Works

– Record set are usually provide by database classes (JDBC or ADO.NET)

– Look exactly like the results of a database query

– Provides abstraction from the database code When to Use It

– When you need a common way to manipulate data from a relational database

Page 33: L04 base patterns
Page 34: L04 base patterns

Summary Base Patterns

– Gateway, Mapper, Layerd Supertype, Separated Interface, Registry, Value Object, Plugin, Service Stub, Record Set

Next: From Problem to Patterns– Using design patterns

Page 35: L04 base patterns

QUIZ

Page 36: L04 base patterns

Question #1 You use this patterns when you need to

break a dependency between two parts of the system

A) RegistryB) GatewayC) Separated InterfaceD) Plugin

Page 37: L04 base patterns

Question #2 Intent of a pattern is this: An object

that sets up communication between two objects

A) GatewayB) MapperC) RegistryD) Value Object

Page 38: L04 base patterns

Question #3 Sketch of a pattern is his

A) PluginB) MapperC) RegistryD) Service Stub

Page 39: L04 base patterns

Question #4 Use this pattern when you find that

dependence on a particular service is hindering your development and testing

A) MapperB) Record SetC) Service StubD) Gateway

Page 40: L04 base patterns

Using Design Patterns

Page 41: L04 base 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

Page 42: L04 base patterns

From Problem to Pattern How do I reuse common functionality of

my objects?–Layered Supertype

How do I access an external service without becoming too dependant on it?–Gateway

How do I avoid creating unwanted dependencies?–Separated Interface

Page 43: L04 base patterns

From Problem to Pattern How do I test my client code using a

service that I don’t have access to?–Service Stub

How do I link to my implementation class using configuration–Plugin

How can I keep common object available within the application–Registry

Page 44: L04 base patterns

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 45: L04 base patterns

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 46: L04 base patterns

The Danger Code Dept

“I’ll fix it later”

The four most dangerous and expensive words in programming

Page 47: L04 base patterns

MailService

Page 48: L04 base patterns

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 49: L04 base patterns

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 50: L04 base patterns

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 51: L04 base patterns

Gateway (466)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

Page 52: L04 base patterns

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 53: L04 base patterns

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 54: L04 base patterns

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 55: L04 base patterns

MailSender Problem

– Many parameters instead of an object– Mail server is hard-coded– Exception handling is bad

public void send(String from, String to, String subject, String body) { String smtpServer = ”smtp.ru.is"; try { ... } catch (Exception ex) { ex.printStackTrace(); } }}

Page 56: L04 base patterns

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 57: L04 base patterns

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 58: L04 base patterns

TestingTestMail: sending mail.Done.

NOTE: mail.ru.is is not good for testing!

Page 59: L04 base patterns

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 60: L04 base patterns

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 61: L04 base patterns

Plugin (499)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

Page 62: L04 base patterns

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 63: L04 base patterns

Improvements Problem

– Can we make the loading of properties and class more generic?

– Other factories might need this functionality also Solution:

– Create a Layered Supertype– MailFactory extends Factory

Page 64: L04 base patterns

Layer Supertype (475)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

Page 65: L04 base patterns

Layer Supertype (475)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

Page 66: L04 base patterns

Plugin Pattern

Page 67: L04 base patterns

Factory Has two methods

– loadProperties– loadClass

Exception handling– Create a new exception class that we will use– FactoyException– Log the error

Page 68: L04 base patterns

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 69: L04 base patterns

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 70: L04 base patterns

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 71: L04 base patterns

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 72: L04 base patterns

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 73: L04 base patterns

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 74: L04 base patterns

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 75: L04 base patterns

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 76: L04 base patterns

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 77: L04 base patterns

Service Stub (504)Removes dependence upon problematic

services during testing Enterprise systems often need to access

external system– Can be out of developers control

Page 78: L04 base patterns

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 79: L04 base patterns

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 80: L04 base patterns

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 81: L04 base patterns

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 82: L04 base patterns

Injecting the Mail Server Name

Page 83: L04 base patterns

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 84: L04 base patterns

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 85: L04 base patterns

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 86: L04 base patterns

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 87: L04 base patterns

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 88: L04 base patterns

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


Recommended