Синглтон краще підходити з точки зору тестування. На відміну від статичних класів, одиночний може реалізувати інтерфейси, і ви можете використовувати екземпляр макету та вводити їх.
У наведеному нижче прикладі я проілюструю це. Припустимо, у вас є метод isGoodPrice (), який використовує метод getPrice (), а ви реалізуєте getPrice () як метод в одиночному.
синглтон, який забезпечує функцію getPrice:
public class SupportedVersionSingelton {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
// calculate price logic here
return 0;
}
}
Використання getPrice:
public class Advisor {
public boolean isGoodDeal(){
boolean isGoodDeal = false;
ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
int price = supportedVersion.getPrice();
// logic to determine if price is a good deal.
if(price < 5){
isGoodDeal = true;
}
return isGoodDeal;
}
}
In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
Make your singleton implement an interface and inject it.
public interface ICalculator {
int getPrice();
}
Остаточна реалізація Singleton:
public class SupportedVersionSingelton implements ICalculator {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
return 0;
}
// for testing purpose
public static void setInstance(ICalculator mockObject){
if(instance != null ){
instance = mockObject;
}
тестовий клас:
public class TestCalculation {
class SupportedVersionDouble implements ICalculator{
@Override
public int getPrice() {
return 1;
}
}
@Before
public void setUp() throws Exception {
ICalculator supportedVersionDouble = new SupportedVersionDouble();
SupportedVersionSingelton.setInstance(supportedVersionDouble);
}
@Test
public void test() {
Advisor advidor = new Advisor();
boolean isGoodDeal = advidor.isGoodDeal();
Assert.assertEquals(isGoodDeal, true);
}
}
У випадку, якщо ми застосуємо альтернативу використання статичного методу для реалізації getPrice (), важко було знущатися над getPrice (). Ви можете знущатися над статикою за допомогою енергетичного знущання, але не весь продукт міг би її використовувати.
getInstance()
методу щоразу, коли ви бажаєте його використовувати (хоча, мабуть, у більшості випадків це не має значення ).