[JAVA] Why implement with a singleton instead of a static method

Question

When I was defining the class with the singleton pattern myself, I suddenly wondered, so I looked it up. What is that question

Why implement with a singleton instead of a class method

about it. As I went deeper into this, I didn't understand why I was implementing the class using the singleton pattern in the first place.

What do you mean

In my private project, I wanted a class for managing properties, so I implemented the following:

PropertyService.java


import java.util.HashMap;
import java.util.Map;

public class PropertyService {

	private static final PropertyService INSTANCE = new PropertyService();
	private Map<String, String> props = new HashMap<String, String>();

	private PropertyService(){
		initializeProps();
	}

	public static PropertyService getInstance() {
		return INSTANCE;
	}

	private void initializeProps() {
		//Implement a method that initializes the property
		//Insert the value manually for convenience.
		props.put("a", "Tanaka");
		props.put("b", "Suzuki");
		props.put("c", "Sato");
	}

	public String getVal(String key) {
		return this.props.get(key);
	}

}

The above implementation has a singleton pattern. For me, I thought, "Because we need to be able to manage properties that are common to the project, we should use the" singleton pattern "that is implemented so that there is always one instance." However, it can also be implemented as follows using the above class and class method.

PropertyUtils.java


import java.util.HashMap;

public class PropertyUtils {

	private static final HashMap<String, String> props = new HashMap<String, String>();

	static {
		//Property initialization process
		props.put("a", "Tanaka");
		props.put("b", "Suzuki");
		props.put("c", "Sato");
	}

	public static String getVal(String key) {
		return props.get(key);
	}

}

It's a so-called utility class. This is easier to implement and seems to be able to centrally manage properties.

So why do we need to implement the singleton pattern? Why do we need "*** always only one instance ***" instead of implementing it in a class method?

If you need to use the singleton pattern

If you want to implement an interface

For example, if you want to implement an interface, you cannot substitute it with a static method.

TestInterface.java


public interface TestInterface {

	public void sayHello(String name);

}

TestImplements.java


public class TestImplements implements TestInterface {

	private static final TestImplements INSTANCE = new TestImplements();

    private TestImplements() {}

    public static TestImplements getInstance() {
        return INSTANCE;
    }

    @Override
    public void sayHello(String name) {
        System.out.println("Hello " + name + " !");
    }

}

Of course, you can define a static method in the interface and define a static method with the same name in the implementation class, but it will be treated as a completely different method, not an override, so the advantage of implementing the interface Is gone. Rather, if you define a static method in the interface, you can use that method without creating an implementation class, so if you want to implement the interface as described above, you still have to use the singleton pattern.

When implementing static method in interface


public interface TestInterface {

	public static void sayHello(String name) { 
		System.out.println("Hello " + name + " !");
	}

}

You can use static methods without implementing them


public class TestImplements implements TestInterface {

	...(Omission)...

	public static void sayHello(String name) {
		TestInterface.sayHello(name);
	}

}

If you want to implement it as an inheritance class of an abstract class

When overriding a method of an abstract class, the static modifier cannot be added, so it must be implemented as a singleton pattern.

TestAbstract.java


abstract public class TestAbstract {

    abstract public void sayHello(String name);

}

TestExtends.java


public class TestExtends extends TestAbstract {

	private static final TestExtends INSTANCE = new TestExtends();

    private TestExtends() {}

    public static TestExtends getInstance() {
        return INSTANCE;
    }

	@Override
	public void sayHello(String name) {
		System.out.println("Hello" + name + " !");
	}

}

If you want to set to DI

For example, if you want to define a bean in spring, you must set an instance of the class as a bean. So if you want to make it a common class for your app and set that class as DI, you need to implement it in a singleton pattern.

If you want to set it to Spring Bean


@Configuration
public class BeanConfiguration {

	@Bean
	public TestInterface testInterface() {
		return TestImplements.getInstance();
	}

}

If you want to inject dependencies

For example, if you want to inject a dependency with Autowired such as spring, the field to be injected cannot be static, so you need to implement it with a singleton pattern.

python


public class TestImplements implements TestInterface {
	
	...(Omission)...
	
	@Autowired
	TestService testService;

	...(Omission)...

}

However, although there is a way to inject dependencies into static fields, it seems to be a rather brute force implementation (see the site for reference).

You can inject dependencies into static fields


public class TestImplements implements TestInterface {

	...(Omission)...
	
	static TestService testService;

	@Autowired
	public void setTestService(TestService service) {
		testService = service;
	}
	
	...(Omission)...

}

But after all, the setter needs to be non-static, so it must be implemented in a singleton pattern.

When you don't have to use a singleton

When not holding the state

For example, in the case of "a class that implements only a method that always returns only a fixed value" like the following class, there is no reason to implement it in the singleton pattern.

TestSingleton.java


public class TestSingleton {

	private static final TestSingleton INSTANCE = new TestSingleton();

	private TestSingleton() {}

	public static TestSingleton getInstance() {
		return INSTANCE;
	}

	public void sayHello() {
		System.out.println("HelloWorld");
	}

}

In the case of the above class, you can implement it as a utility class as mentioned at the beginning.

Summary

This time, I was wondering why the singleton "only one instance can be created" design is advantageous for creating applications, so I studied it. The reason I thought about that is that, as mentioned above, *** some singletons can be replaced by static methods. *** *** When I wanted to use the singleton pattern in this study, I thought I had to find the advantage because it was the only "*** instance ***".

I have listed the cases where the singleton pattern should be implemented and the cases where it should not be implemented as far as I can think of, but I will add it as needed if I notice anything in the future.

reference: I tried to summarize the usage of the Singleton pattern Pros and Cons of Singleton. Carefully explain Java static methods! Let's learn usage examples and ideas together! I want to target static fields to @Autowired

Recommended Posts

Why implement with a singleton instead of a static method
Quickly implement a singleton with an enum in Java
Benefits of Java static method
Implement UICollectionView of iOS14 with CustomCell.
Use a named format with Ruby's format method
[Java] Why use StringUtils.isEmpty () instead of String.isEmpty ()
I tried to implement a function equivalent to Felica Lite with HCE-F of Android
Come out with a suffix on the method
Come out with a suffix on the method 2
Why use setters/getters instead of public/private in Java