BAEL-4933 | Differences between static classes and the singleton pattern in Java (#11014)

* BAEL-4220 | A Guide to IllegalAccessError and when it happens

* BAEL-4220 | A Guide to IllegalAccessError and when it happens | fix tests

* BAEL-4220 | A Guide to IllegalAccessError and when it happens | fix tests

* BAEL-4220 | A Guide to IllegalAccessError and when it happens | BDD test names

* BAEL-4494 | .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?

* BAEL-4494 | .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?

* BAEL-4933 | Differences between static classes and the singleton pattern in Java

Co-authored-by: root <anmoldeep0123@gmail.com>
This commit is contained in:
anmoldeep0123 2021-07-09 14:57:55 +05:30 committed by GitHub
parent 1910561a54
commit 37db34cb8a
9 changed files with 246 additions and 0 deletions

View File

@ -0,0 +1,30 @@
package com.baeldung.staticsingletondifference;
public class CachingSingleton implements SingletonInterface {
private CachingSingleton() {
}
private static class SingletonHolder {
public static final CachingSingleton instance = new CachingSingleton();
}
public static CachingSingleton getInstance() {
return SingletonHolder.instance;
}
@Override
public String describeMe() {
return "Caching Responsibilities";
}
@Override
public String passOnLocks(MyLock lock) {
return lock.takeLock(1);
}
@Override
public void increment() {
throw new UnsupportedOperationException("Not Supported Here");
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.staticsingletondifference;
public class FileSystemSingleton implements SingletonInterface{
private int filesWritten;
private FileSystemSingleton() {
}
private static class SingletonHolder {
public static final FileSystemSingleton instance = new FileSystemSingleton();
}
public static FileSystemSingleton getInstance() {
return SingletonHolder.instance;
}
@Override
public String describeMe() {
return "File System Responsibilities";
}
@Override
public String passOnLocks(MyLock lock) {
return lock.takeLock(2);
}
@Override
public void increment() {
this.filesWritten++;
}
public int getFilesWritten() {
return filesWritten;
}
}

View File

@ -0,0 +1,8 @@
package com.baeldung.staticsingletondifference;
public class MyLock {
protected String takeLock(int locks) {
return "Taken Specific Lock";
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.staticsingletondifference;
import java.io.ObjectStreamException;
import java.io.Serializable;
public class SerializableCloneableSingleton implements SingletonInterface, Serializable, Cloneable {
private static final long serialVersionUID = -1917003064592196223L;
private int state;
private SerializableCloneableSingleton() {
}
private static class SingletonHolder {
public static final SerializableCloneableSingleton instance = new SerializableCloneableSingleton();
}
public static SerializableCloneableSingleton getInstance() {
return SingletonHolder.instance;
}
@Override
public String describeMe() {
throw new UnsupportedOperationException("Not Supported Here");
}
@Override
public String passOnLocks(MyLock lock) {
throw new UnsupportedOperationException("Not Supported Here");
}
@Override
public void increment() {
this.state++;
}
public int getState() {
return state;
}
private Object readResolve() throws ObjectStreamException {
return SingletonHolder.instance;
}
public Object cloneObject() throws CloneNotSupportedException {
return this.clone();
}
}

View File

@ -0,0 +1,10 @@
package com.baeldung.staticsingletondifference;
public interface SingletonInterface {
public String describeMe();
public String passOnLocks(MyLock lock);
public void increment();
}

View File

@ -0,0 +1,20 @@
package com.baeldung.staticsingletondifference;
public class SingletonLock extends MyLock {
private SingletonLock() {
}
private static class SingletonHolder {
public static final SingletonLock instance = new SingletonLock();
}
public static SingletonLock getInstance() {
return SingletonHolder.instance;
}
@Override
public String takeLock(int locks) {
return "Taken Singleton Lock";
}
}

View File

@ -0,0 +1,8 @@
package com.baeldung.staticsingletondifference;
public class SubUtility extends SuperUtility {
public static String echoIt(String data) {
return data;
}
}

View File

@ -0,0 +1,8 @@
package com.baeldung.staticsingletondifference;
public class SuperUtility {
public static String echoIt(String data) {
return "SUPER";
}
}

View File

@ -0,0 +1,77 @@
package com.baeldung.staticsingletondifference;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.stream.IntStream;
import org.junit.Assert;
import org.junit.Test;
public class ForSingletonsUnitTest {
@Test
public void whenStaticUtilClassInheritance_thenOverridingFails() {
SuperUtility superUtility = new SubUtility();
Assert.assertNotEquals("ECHO", superUtility.echoIt("ECHO"));
Assert.assertEquals("SUPER", superUtility.echoIt("ECHO"));
}
@Test
public void whenSingletonDerivesBaseClass_thenRuntimePolymorphism() {
MyLock myLock = new MyLock();
Assert.assertEquals("Taken Specific Lock", myLock.takeLock(10));
myLock = SingletonLock.getInstance();
Assert.assertEquals("Taken Singleton Lock", myLock.takeLock(10));
}
@Test
public void whenSingletonImplementsInterface_thenRuntimePolymorphism() {
SingletonInterface singleton = FileSystemSingleton.getInstance();
Assert.assertEquals("File System Responsibilities", singleton.describeMe());
singleton = CachingSingleton.getInstance();
Assert.assertEquals("Caching Responsibilities", singleton.describeMe());
}
@Test
public void whenSingleton_thenPassAsArguments() {
SingletonInterface singleton = FileSystemSingleton.getInstance();
Assert.assertEquals("Taken Singleton Lock", singleton.passOnLocks(SingletonLock.getInstance()));
}
@Test
public void whenSingleton_thenAllowState() {
SingletonInterface singleton = FileSystemSingleton.getInstance();
IntStream.range(0, 5)
.forEach(i -> singleton.increment());
Assert.assertEquals(5, ((FileSystemSingleton) singleton).getFilesWritten());
}
@Test
public void whenSingleton_thenAllowSerializationDeserialization() {
SingletonInterface singleton = SerializableCloneableSingleton.getInstance();
singleton.increment();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
new ObjectOutputStream(baos).writeObject(singleton);
SerializableCloneableSingleton singletonNew = (SerializableCloneableSingleton) new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject();
Assert.assertEquals(1, singletonNew.getState());
Assert.assertEquals(singleton.hashCode(), singletonNew.hashCode());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void whenSingleton_thenAllowCloneable() {
SerializableCloneableSingleton singleton = SerializableCloneableSingleton.getInstance();
singleton.increment();
try {
Assert.assertEquals(2, ((SerializableCloneableSingleton) singleton.cloneObject()).getState());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}