49
1 01/16/22 1 Design Patterns Week 1 : Introduction and Singleton Jon Simon [email protected]

Introduction to Design Patterns and Singleton

Embed Size (px)

DESCRIPTION

This is Class 1 on a 6 week course I taught on Software Design Patterns. This course provides an introduction into Design Patterns and delves into the Singleton Pattern. Class based on "Head First Design Patterns."

Citation preview

Page 1: Introduction to Design Patterns and Singleton

104/10/23 1

Design Patterns

Week 1 : Introduction and Singleton

Jon [email protected]

Page 2: Introduction to Design Patterns and Singleton

Agenda Introduction to Design Patterns

What is a Design Pattern Why Study Design Patterns History of Design Patterns The Gang of Four Tangent: Unit Testing The Book: Head First Design Patterns

The Singleton Pattern Logger Example Lazy Instantiation Singleton vs. Static Variables Threading: Simple, Double-Checked, Eager Initialization Lab Inheritance Add Registry to Singleton Dependencies Unit Testing Articles

2

Page 3: Introduction to Design Patterns and Singleton

3

What is a Design Pattern?

• A problem that someone has already solved.• A model or design to use as a guide

• More formally: “A proven solution to a common problem in a specified context."

Real World Examples Blueprint for a house Manufacturing

304/10/23

Page 4: Introduction to Design Patterns and Singleton

4404/10/23

Why Study Design Patterns?

Provides software developers a toolkit for handling problems that have already been solved.

Provides a vocabulary that can be used amongst software developers. The Pattern Name itself helps establish a vocabulary

Helps you think about how to solve a software problem.

Page 5: Introduction to Design Patterns and Singleton

5504/10/23

History of Design Patterns

Christopher Alexander (Civil Engineer) in 1977 wrote “Each pattern describes a problem which occurs over and over

again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.”

Each pattern has the same elements Pattern Name – helps develop a catalog of common problems Problem – describes when to apply the pattern. Describes

problem and its context. Solution – Elements that make up the design, their

relationships, responsibilities, and collaborations. Consequences – Results and trade-offs of applying the pattern

Page 6: Introduction to Design Patterns and Singleton

6

History (continued)

In 1995, the principles that Alexander established were applied to software design and architecture. The result was the book:

“Design Patterns: Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.

Also commonly known as “The Gang of Four”.

604/10/23

Page 7: Introduction to Design Patterns and Singleton

7

The Gang of Four

Defines a Catalog of different design patterns.

Three different types Creational – “creating objects in a manner suitable for the

situation” Structural – “ease the design by identifying a simple way to

realize relationships between entities” Behavorial – “common communication patterns between

objects”

704/10/23

Page 8: Introduction to Design Patterns and Singleton

8

The Gang of Four: Pattern Catalog

CreationalAbstract FactoryBuilderFactory MethodPrototypeSingleton

StructuralAdapterBridgeCompositeDecoratorFaçadeFlyweightProxy

BehavioralChain of ResponsibilityCommandInterpreterIteratorMediatorMementoObserverStateStrategyTemplate MethodVisitor

804/10/23

Patterns in red will be discussed in class.

Page 9: Introduction to Design Patterns and Singleton

9

How Design Patterns Solve Design Problems From Gang of Four.

Finding Appropriate Objects Determine Object Granularity Specify Object Interfaces Specifying Object Implementations

Programming to an Interface, not an Implementation

Encourage Reusability Inheritance versus Composition Delegation

Support Extensibility Frameworks

904/10/23

Page 10: Introduction to Design Patterns and Singleton

10

Reality

Problems with design early on It is sometimes very hard to “see” a design pattern. Not all requirements are known. A design that is applicable early on becomes obsolete. “Paralysis by Analysis”

Due to these realities, refactoring is inevitable!

Question: How do you mitigate the fact that you won’t have all of the design figured out?

1004/10/23

Page 11: Introduction to Design Patterns and Singleton

11

Tangent: Unit Testing

If you create unit tests early in the development cycle, then it will be easier to refactor later on when more requirements are known. As a developer, you will have more confidence to make good

design adjustments. Good design adjustments may lead to better maintainability of

the code!

What happens if you do not have Unit Tests early on? These statements may be heard: “ I am afraid to breaking something.” “I know the right thing to do….but I am not going to do it because

the system may become unstable.” You may incur “Technical Debt” if you do not refactor well

1104/10/23

Page 12: Introduction to Design Patterns and Singleton

12

Unit Testing (cont)

Unit Testing leads to easier Refactoring With easier Refactoring, you can take the risk of applying

Design Patterns, even if it means changing a lot of code. Applying Design Patterns can decrease Technical Debt and

improve the maintainability and extendibility of your system.

Therefore…it pays to Unit Test!

1204/10/23

Page 13: Introduction to Design Patterns and Singleton

13

Unit Testing: Final Thoughts

Make unit testing part of the project culture.

When creating a schedule, include unit testing in your estimates.

Create your unit tests before you write the code. This helps define “Doneness” Helps you think about how software needs to be layered…it may

actually lead to more refactoring!

1304/10/23

Page 14: Introduction to Design Patterns and Singleton

141404/10/23

Common Pitfall

“I just learned about Design Pattern XYZ. Let’s use it!”

Reality: If you are going to use a Design Pattern, you should have a reason to do so.

The software requirements should really drive why you are going to use (or not use) a Design Pattern.

Page 15: Introduction to Design Patterns and Singleton

151504/10/23

The Book

“Head First Design Patterns” Eric Freeman & Elisabeth Freeman

Book is based on the Gang of Four design patterns.

Easier to read.

Examples are fun, but not necessarily “real world”.

Page 16: Introduction to Design Patterns and Singleton

16

Example: Logger

What is wrong with this code?

public class Logger

{

public Logger() { }

public void LogMessage() {

//Open File "log.txt"

//Write Message

//Close File

}

}

Page 17: Introduction to Design Patterns and Singleton

17

Example: Logger (cont)

Since there is an external Shared Resource (“log.txt”), we want to closely control how we communicate with it.

We shouldn’t have to create the Logger class every time we want to access this Shared Resource. Is there any reason to?

We need ONE.

Page 18: Introduction to Design Patterns and Singleton

181804/10/23

Singleton GoF Definition: “The Singleton Pattern ensures a class

has only one instance, and provides a global point of access to it.”

Best Uses Logging Caches Registry Settings Access External Resources

Printer Device Driver Database

Page 19: Introduction to Design Patterns and Singleton

191904/10/23

Logger – as a Singleton

public class Logger{ private Logger{}

private static Logger uniqueInstance;

public static Logger getInstance() {

if (uniqueInstance == null) uniqueInstance = new Logger();

return uniqueInstance;

}}

Note the parameterless constructor

See pg 173 in book

Page 20: Introduction to Design Patterns and Singleton

20

Lazy Instantiation Objects are only created when it is needed

Helps control that we’ve created the Singleton just once.

If it is resource intensive to set up, we want to do it once.

2004/10/23

Page 21: Introduction to Design Patterns and Singleton

21

Singleton vs. Static Variables

What if we had not created a Singleton for the Logger class??

Let’s pretend the Logger() constructor did a lot of setup.

In our main program file, we had this code:

public static Logger MyGlobalLogger = new Logger();

All of the Logger setup will occur regardless if we ever need to log or not.

Page 22: Introduction to Design Patterns and Singleton

22

Threading

public class Singleton

{

private Singleton() {}

private static Singleton uniqueInstance;

public static Singleton getInstance()

{

if (uniqueInstance == null)

uniqueInstance = new Singleton();

return uniqueInstance;

}

}

2204/10/23

What would happen if two different threads accessed this line at the same time?

Page 23: Introduction to Design Patterns and Singleton

23

Option #1: Simple Locking

public class Singleton{ private Singleton() {}

private static Singleton uniqueInstance;

public static Singleton getInstance() { synchronized(Singleton.class) { if (uniqueInstance == null) uniqueInstance = new Singleton(); }

return uniqueInstance; }}

Page 24: Introduction to Design Patterns and Singleton

24

Option #2 – Double-Checked Locking

public class Singleton{ private Singleton() {}

private volatile static Singleton uniqueInstance;

public static Singleton getInstance() { if (uniqueInstance == null) {

synchronized(Singleton.class) { if (uniqueInstance == null) uniqueInstance = new Singleton(); }

}

return uniqueInstance; }}

pg 182

Page 25: Introduction to Design Patterns and Singleton

252504/10/23

Option #2 (C# Example)

public class Singleton

{

private Singleton() {}

private static object syncRoot = new Object();

private static volatile Singleton instance;

public static Singleton Instance

{

get {

if (instance == null) //first check

{

lock (syncRoot)

{

if (instance == null) //second check

instance = new Singleton();

}

}

return instance;

}

}

}

Page 26: Introduction to Design Patterns and Singleton

26

Option #3: “Eager” Initialization

public class Singleton

{

private Singleton() {}

private static Singleton uniqueInstance = new Singleton()

public static Singleton getInstance()

{

return uniqueInstance;

}

}

2604/10/23

1. Instance is created the first time any member of the class is referenced.

2. Good to use if the application always creates; and if little overhead to create.

Runtime guarantees that this is thread-safe

pg 181

Page 27: Introduction to Design Patterns and Singleton

27

Lab #1: Turn a class into a Singleton

public class Logger {

public Logger() { }

public void WriteLine(string text) { }

public string ReadEntireLog()

{

return “Log Entries Here”;

}

}

2704/10/23

Take this class and turn it into a Singleton.

Page 28: Introduction to Design Patterns and Singleton

28

Lab #1 Answer

public class Logger { private Logger() { }

private static Logger instance; public static Logger getInstance() { if (instance == null) instance = new Logger();

return instance; }

//Functions. . .

Page 29: Introduction to Design Patterns and Singleton

Lab #2 public class BaseSingleton {

private BaseSingleton() { }

private static BaseSingleton instance;

public static BaseSingleton getInstance()

{

if (instance == null) {

instance = new BaseSingleton();

}

return instance;

}

//Some state variables

protected int someInt;

//Function is marked as virtual so that it can be overidden

public void DoSomething() {

someInt = 1;

}

}

2904/10/23

Page 30: Introduction to Design Patterns and Singleton

Lab #2 (cont)

public class SubClassSingleton extends BaseSingleton

{

private SubClassSingleton() { }

public void DoSomething()

{

someInt = 2;

}

public void NewFunction() {

//new functionality here

}

}

3004/10/23

Page 31: Introduction to Design Patterns and Singleton

Lab #2 (cont)

Question #1: What is wrong with the constructor for SubClassSingleton?

3104/10/23

Page 32: Introduction to Design Patterns and Singleton

Lab #2 (cont)

Here is the code that calls the Singleton:

public class Main

{

public static void DoStuff()

{

01 BaseSingleton.getInstance().DoSomething();

02 SubClassSingleton.getInstance().DoSomething();

03 SubClassSingleton.getInstance().NewFunction();

}

}

3204/10/23

Page 33: Introduction to Design Patterns and Singleton

Lab #2 (cont)

Question #2: For Line 01, what is the value of someInt after it is called?

Question #3: For Line 02, what is the value of someInt after it is called?

Question #4: What is wrong with Line 03?

3304/10/23

Page 34: Introduction to Design Patterns and Singleton

34

Lab #2 Answers

Question #1 : It will not compile. The base constructor must be changed from private to protected.

Question #2 – 1

Question #3 - 1 Even though we have overridden the base, it doesn’t matter. The

base implementation is returned by getInstance().

Question 4 – It will not compile!

Page 35: Introduction to Design Patterns and Singleton

353504/10/23

Inheritance Summary

The sub-class can share state with the base class. Now you have two objects that share state.

“Gang of Four” recommends usages of a registry of Singletons. The base class reads an environment variable to determine which Singleton to use.

Bottom Line: Singletons and Inheritance do not mix well.

Page 36: Introduction to Design Patterns and Singleton

36

Add Registry to Singleton public class BaseSingleton { protected BaseSingleton() { }

private static HashMap map = new HashMap();

public static BaseSingleton getInstance(String classname) { //First, attempt to get Singleton from HashMap BaseSingleton singleton = (BaseSingleton)map.get(classname);

if (singleton != null) return singleton; else { //Singleton not found if (classname.Equals("SubClassSingleton")) singleton = new SubClassSingleton(); else ......

//Add singleton to HashMap so we can get it again map.put(classname, singleton);

return singleton; }

Page 37: Introduction to Design Patterns and Singleton

37

SingletonRegistry Class

Source http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-design

patterns.html?page=6

Describes a SingletonRegistry whose purpose is to store Singletons!

public static Singleton getInstance() { return (Singleton)SingletonRegistry.REGISTRY.getInstance(classname); }

Page 38: Introduction to Design Patterns and Singleton

38

Case Study: Dependenciespublic class Searcher

{

//Singleton Setup code Here

public Collection FindCustomers(String criteria) {

String conStr = GetConnectionFromRegistry();

OracleConnection conn = new OracleConnection(conStr);

//Query database using criteria

return (Collection of customers);

}

}

3804/10/23

Page 39: Introduction to Design Patterns and Singleton

39

Case Study: Dependencies

To search the database, the client code would need to do the following:

Searcher.getInstance().FindCustomers(“some criteria”)

What happens if we need to change the database to SQL Server? Or change how we get the connection string?

Page 40: Introduction to Design Patterns and Singleton

40

Case Study: Dependencies The Singleton is tightly coupled to Oracle. If the

database changed in the future, this object would need to be changed. It is also tightly coupled in how it retrieves the connection string.

The Singleton hides object dependencies (Oracle and registry). Anyone using the Singleton would need to inspect the internals to find out what is really going on.

Possibly memory leak since the Singleton may hold onto the resource for an infinite amount of time.

4004/10/23

Page 41: Introduction to Design Patterns and Singleton

41

Unit Testing

There are many problems with unit testing a Singleton.

Problem: If you are running multiple unit tests that accesses the same Singleton, the Singleton will retain state between unit tests. This may lead to undesired results!

Solution : Use Reflection to get access to the private static instance variable. Then set it to null. This should be done at the end of each unit test.

private static Singleton uniqueInstance;

4104/10/23

Page 42: Introduction to Design Patterns and Singleton

Unit Testing

Other problems

You want to unit test a method of a Singleton, but the method refers to other external resources. It is hard to inject a mock in this case.

You are unit testing a method that does a lot of business logic. One of the method calls is a Singleton that accesses an external resource. How can you replace the Singleton with a mock call?

4204/10/23

Page 43: Introduction to Design Patterns and Singleton

43

Scott Densmore “Why Singletons are Evil”

“…the dependencies in your design are hidden inside the code, and not visible by examining the interfaces of your classes and methods. You have to inspect the code to understand exactly what other objects your class uses.

“Singletons allow you to limit creation of your objects... you are mixing two different responsibilities into the same class.”

“Singletons promote tight coupling between classes.” “Singletons carry state with them that last as long as the program

lasts…Persistent state is the enemy of unit testing.”

Source: http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx

4304/10/23

Page 44: Introduction to Design Patterns and Singleton

444404/10/23

Jeremy D. Miller “Chill out on the Singleton…”

“Using a stateful singleton opens yourself up to all kinds of threading issues. When you screw up threading safety you can create really wacky bugs that are devilishly hard to reproduce.

My best advice is to not use caching via static members until you absolutely have to for performance or resource limitation reasons.”

Source: http://codebetter.com/blogs/jeremy.miller/archive/2005/08/04/130302.aspx

Page 45: Introduction to Design Patterns and Singleton

454504/10/23

“How to Decontaminate a Singleton”

“Define a Spring bean for each Singleton you use. For new DI-like implementations use the Spring bean as a wrapper that allows to access the functionality of the Singleton.”

http://blog.rainer.eschen.name/2006/12/15/how-to-decontaminate-a-singleton/

Page 46: Introduction to Design Patterns and Singleton

Comments from Others

“Sub-classing or creating mocks for Singletons is impossible (unless it implements an interface for its type)”

“It really should only be used in cases of classes for Constants for example.”

“Access to a singleton in an application must be serialized, which complicates multi-threading issues in applications hence introducing possible issues of thread locking.”

4604/10/23

Page 47: Introduction to Design Patterns and Singleton

Comments from Others “I had cases where I wanted to create a subclass, and

the singleton kept referring to the superclass.”

“..writing a good unit test was impossible because the class invoked a singleton, and there was no way to inject a fake.”

“Unit testing a singleton is not so much a problem as unit testing the other classes that use a singleton. They are bound so tightly that there is often no way to inject a fake (or mock) version of the singleton class. In some cases you can live with that, but in other cases, such as when the singleton accesses an external resource like a database, it's intolerable for a unit test.” 4704/10/23

Page 48: Introduction to Design Patterns and Singleton

48

Other Useful Articles

Singleton Explained http://c2.com/cgi/wiki?SingletonPattern http://www.oodesign.com/singleton-pattern.html

Unit Testing http://imistaken.blogspot.com/2009/11/unit-testing-

singletons.html http://weblogs.asp.net/okloeten/archive/2004/08/19/217182.aspx

Page 49: Introduction to Design Patterns and Singleton

49

SUMMARY

Pattern Name – Singleton Problem – Ensures one instance of an object and global

access to it. Solution

Hide the constructor Use static method to return one instance of the object

Consequences Lazy Instantiation Threading Inheritance issues Hides dependencies Difficult unit testing

4904/10/23