• Keine Ergebnisse gefunden

Design Patterns and Refactoring Singleton Oliver Haase

N/A
N/A
Protected

Academic year: 2022

Aktie "Design Patterns and Refactoring Singleton Oliver Haase"

Copied!
23
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Design Patterns and Refactoring

Singleton

Oliver Haase

HTWG Konstanz

(2)

Description I

Classification: object based creational pattern Puropse:

ensure that a class can be instantiatedexactly once provide global access point to single instance Application Examples:

exactly one driver for a piece if hardware (e.g. printer) exactly one socket listener that receives incoming requests application that can be started only once

global event queue fordiscrete event simulation

(3)

Description II

Structure:

Members:

Singleton

responsible for creation of the instance

provides static operation for access to the instance

Interactions: clients access singleton instance through getInstance operation

(4)

Description III

Alternative: Class with static variables and static methods Drawbacks:

Java interfaces cannot contain static methods

→ class cannot be hidden behind interface each method invocation contains class name

→ undermines polymorphism

(5)

Description III

Alternative: Class with static variables and static methods

Drawbacks:

Java interfaces cannot contain static methods

→ class cannot be hidden behind interface each method invocation contains class name

→ undermines polymorphism

(6)

Implementation

Singleton implementation with Lazy Instantiation

1 p u b l i c c l a s s M y S i n g l e t o n {

2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {

4 . . .

5 }

6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l ) {

8 i n s t a n c e = new M y S i n g l e t o n ( ) ;

9 }

10 r e t u r n i n s t a n c e ;

11 }

12 . . .

13 }

Problem: Can lead to several instances if thread gets interrupted between lines 7 and 8

→ not thread-safe!

(7)

Implementation

Singleton implementation with Lazy Instantiation

1 p u b l i c c l a s s M y S i n g l e t o n {

2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {

4 . . .

5 }

6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l ) {

8 i n s t a n c e = new M y S i n g l e t o n ( ) ;

9 }

10 r e t u r n i n s t a n c e ;

11 }

12 . . .

13 }

Problem: Can lead to several instances if thread gets interrupted between lines 7 and 8

→ not thread-safe!

(8)

Implementation

Singleton implementation with Lazy Instantiation

1 p u b l i c c l a s s M y S i n g l e t o n {

2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {

4 . . .

5 }

6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l ) {

8 i n s t a n c e = new M y S i n g l e t o n ( ) ;

9 }

10 r e t u r n i n s t a n c e ;

11 }

12 . . .

13 }

Problem: Can lead to several instances if thread gets interrupted between lines 7 and 8

→ not thread-safe!

(9)

Implementation

Resolve concurrency problem through synchronization:

p u b l i c c l a s s M y S i n g l e t o n {

p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; p r i v a t e M y S i n g l e t o n ( ) {

. . . }

p u b l i c s t a t i c s y n c h r o n i z e d M y S i n g l e t o n g e t I n s t a n c e ( ) {

i f ( i n s t a n c e == n u l l ) {

i n s t a n c e = new M y S i n g l e t o n ( ) ; }

r e t u r n i n s t a n c e ; }

. . . }

(10)

Implementation

Problem: Only first call of getInstance needs to be synchronized:

→ unnecessary reduction of concurrency

→ synchronized Methodsalwaysslower than unsynchronized methods:

test program with 109 sequentialgetInstance calls on Mac Mini, 2 GHz Intel Core 2 Duo, 1 GB RAM, 120 GB hard drive:

unsynchronized 4 sec.

synchronized 58 sec.

(11)

Implementation

Implementation with Checked Locking

1 p u b l i c c l a s s M y S i n g l e t o n {

2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {

4 . . .

5 }

6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l) {

8 s y n c h r o n i z e d ( M y S i n g l e t o n .c l a s s ) { 9 i n s t a n c e = new M y S i n g l e t o n ( ) ;

10 }

11 }

12 r e t u r n i n s t a n c e ;

13 }

14 . . .

15 }

(12)

Implementation

Scenario:

Thread1 gets interrupted between lines 8 and 9 → holds monitor of MySingleton class object, no singleton instance created yet.

Thread2 passes 7, waits at 8 for Thread1

Thread1 finishes, creates singleton instance

Thread2 finishes, creates second ‘singleton’ instance

→ not thread-safe!

(13)

Implementation

Solution attempt usingDouble-Checked-Locking-(Anti-)Pattern:

1 p u b l i c c l a s s M y S i n g l e t o n {

2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {

4 . . .

5 }

6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l) {

8 s y n c h r o n i z e d ( M y S i n g l e t o n .c l a s s ) {

9 i f ( i n s t a n c e == n u l l ) {

10 i n s t a n c e = new M y S i n g l e t o n ( ) ;

11 }

12 }

13 }

14 r e t u r n i n s t a n c e ;

15 }

16 . . .

17 }

(14)

Implementation

Problem: Thread scheduling happens on the level of byte code, not on the Java source code level . . . object creation in line 10

i n s t a n c e = new M y S i n g l e t o n ( ) ;

is mapped to the following pseudo byte code

1 ptrMemory = a l l o c a t e M e m o r y ( ) 2 a s s i g n M e m o r y ( i n s t a n c e , ptrMemory ) 3 c a l l M y S i n g l e t o n C o n s t r u c t o r ( i n s t a n c e )

If scheduling takes place between lines 2 and 3 then instance != null, even though

instance has not been properly initialized

⇒ Thread2 might return uninitialized objectinstance, if thread 10 is interrupted withinline 10!

(15)

Implementation

The simple things are often the best— or: Life can be that simple!

→ fully functional, performant solution:

p u b l i c c l a s s M y S i n g l e t o n {

p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = new M y S i n g l e t o n ( ) ;

p r i v a t e M y S i n g l e t o n ( ) { . . .

}

p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { r e t u r n i n s t a n c e ;

} . . . }

(16)

Implementation

Consequences of the simple implementation

Singleton instance is created (exactly once) at class loading time even if it will never be used→ but:

this rarely happens because class loading is usually triggered by usage rather small damage

Time consumption at loading rsther than at first usage → neither better nor worse, only different . . .

potential drawback: class loading order hardly predictable

→ Problem, if one singleton instance is needed to create another

(17)

Implementation

Consequences of the simple implementation

Singleton instance is created (exactly once) at class loading time even if it will never be used→ but:

this rarely happens because class loading is usually triggered by usage rather small damage

Time consumption at loading rsther than at first usage → neither better nor worse, only different . . .

potential drawback: class loading order hardly predictable

→ Problem, if one singleton instance is needed to create another

(18)

Usage

Joi 1 programming language supports singleton pattern:

s i n g l e t o n component MyComponent p r o v i d e s M y I n t e r f a c e { . . .

}

The current Joi implementation maps the Joi code to corresponding Java code.

Reason: Joi doesn’t support static class members

→ static variables are modelled as members of a singleton class

→ frequent usage of the singleton pattern

Java Webstart: Technology for the dynamic download, execution and updating of applications

1more informationen at http://www-home.htwg-konstanz.de/˜haase/hp/joi.html and in [von Drachenfels, Haase, Walter.Joi - eine Java–Spracherweiterung zur Reduzierung von Codeabh¨angigkeiten. In HTWG Forum, 2008/2009]

(19)

Singleton – Additional Considerations

Sometimes, a singleton object needs to be configuredat creation time (or at the time of first usage)

Example: Socket listener that needs to listen on certain port Possible Realizations:

add parameters to getInstancemethod:

p u b l i c c l a s s CS1 {

p r i v a t e s t a t i c CS1 i n s t a n c e = new CS1 ( ) ; p r i v a t e i n t s t a t e ;

p r i v a t e CS1 ( ) {}

p r i v a t e v o i d c o n f i g (i n t s t a t e ) { t h i s. s t a t e = s t a t e ;

}

p u b l i c s t a t i c CS1 g e t I n s t a n c e (i n t s t a t e ) { i n s t a n c e . c o n f i g ( s t a t e ) ;

r e t u r n i n s t a n c e ; }

}

(20)

Singleton – Additional Considerations

two overloadedgetInstancemethods with and w/o parameters

p u b l i c c l a s s CS2 {

p r i v a t e s t a t i c CS2 i n s t a n c e = new CS1 ( ) ; p r i v a t e i n t s t a t e ;

p r i v a t e CS2 ( ) {}

p r i v a t e v o i d c o n f i g (i n t s t a t e ) { t h i s. s t a t e = s t a t e ;

}

p u b l i c s t a t i c CS2 g e t I n s t a n c e (i n t s t a t e ) { i n s t a n c e . c o n f i g ( s t a t e ) ;

r e t u r n i n s t a n c e ; }

p u b l i c s t a t i c CS2 g e t I n s t a n c e ( ) { r e t u r n i n s t a n c e ;

} }

(21)

Singleton – Additional Considerations

getInstancemethod without params + separateconfigmethod;

catch repeatedconfiginvocations

p u b l i c c l a s s CS3 {

p r i v a t e s t a t i c CS3 i n s t a n c e = new CS3 ( ) ; p r i v a t e i n t s t a t e ;

p r i v a t e b o o l e a n c o n f i g u r e d = f a l s e; p r i v a t e CS3 ( ) {}

p u b l i c s y n c h r o n i z e d v o i d c o n f i g (i n t s t a t e ) t h r o w s E x c e p t i o n {

i f ( c o n f i g u r e d )

throw new E x c e p t i o n ( ” a l r e a d y c o n f i g u r e d ” ) ; t h i s. s t a t e = s t a t e ;

t h i s. c o n f i g u r e d = t r u e; }

p u b l i c s t a t i c CS3 g e t I n s t a n c e ( ) { r e t u r n i n s t a n c e ;

}

(22)

Singleton – Additional Considerations

getInstancemethod without params + separate staticconfig method, catch repeated and/or missingconfiginvocations

p u b l i c c l a s s CS4 {

p r i v a t e s t a t i c CS4 i n s t a n c e = new CS4 ( ) ; p r i v a t e i n t s t a t e ;

p r i v a t e s t a t i c b o o l e a n c o n f i g u r e d = f a l s e; p r i v a t e CS4 ( ) {}

(23)

Singleton – Additional Considerations

p u b l i c s t a t i c s y n c h r o n i z e d v o i d c o n f i g (i n t s t a t e ) t h r o w s E x c e p t i o n {

i f ( c o n f i g u r e d ) {

throw new E x c e p t i o n ( ” a l r e a d y c o n f i g u r e d ” ) ; }

i n s t a n c e . s t a t e = s t a t e ; c o n f i g u r e d = t r u e; }

p u b l i c s t a t i c CS4 g e t I n s t a n c e ( ) t h r o w s E x c e p t i o n { i f ( ! c o n f i g u r e d )

throw new E x c e p t i o n ( ” n o t c o n f i g u r e d y e t ” ) ; r e t u r n i n s t a n c e ;

} }

Referenzen

ÄHNLICHE DOKUMENTE

A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior..

Communication is centralized in broker (mediator) object Broker is responsible to preserve consistency. Broker is single point of failure and scalability bottle-neck Communication

plain text documents, even though its functionality is applicable to other document types as well;. Difficult to use document mock-up

Implementor (CommImpl): defines interface for implementation classes (can differ from Abstraction interface). ConcreteImplementor (TcpCommunication): provides implementation

knows which subsystem classes are responsible for which requests delegates client requests to respective subsytem

Purpose: Define method for object creation in abstract class, leave actual creation to concrete subclasses.. Also known as:

When an RMI server object is exported, the runtime system (Java virtual machine) creates a dynamic proxy (RMI stub) that implements the respective remote interface, and forwards

Element: defines an accept operation with a Visitor as argument ConcreteElement: implements the accept operation, usually by calling the visitor’s appropriate visit