Singleton jest lepszym podejściem z perspektywy testowania. W przeciwieństwie do klas statycznych, singleton może implementować interfejsy i można użyć próbnej instancji i wstrzyknąć je.
W poniższym przykładzie zilustruję to. Załóżmy, że masz metodę isGoodPrice (), która używa metody getPrice () i implementujesz getPrice () jako metodę w singletonie.
singleton zapewniający funkcjonalność 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;
}
}
Korzystanie z 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();
}
Ostateczne wdrożenie 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;
}
klasa testowa:
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);
}
}
W przypadku, gdy skorzystamy z alternatywnej metody statycznej do implementacji metody getPrice (), trudno było naśladować metodę getPrice (). Można kpić z elektryczności statycznej, ale nie wszystkie produkty mogą z niego korzystać.
getInstance()
metody za każdym razem, gdy chcesz jej użyć (chociaż prawdopodobnie w większości przypadków nie ma to znaczenia ).