Использование внедрение зависимостей .
//GetSATService returns the fake service during testing
var myService = GetSATService();
var serviceQuestions = myService.GetAllQuestions();
Или, предпочтительно, в конструкторе для объекта установите поле SATService (поэтому конструктору требуется установить SATService. Если вы сделаете это, его будет проще проверить.
Редактировать: Извините, я уточню здесь. То, что у вас есть в вашем коде выше, является связанной зависимостью, где ваш код создает объект, который он использует. Внедрение зависимостей или шаблон Inversion of Control (IOC) заставит вас отсоединить эту зависимость. (Или просто не называйте «новым» - пусть это делает кто-то другой - то, что вы можете контролировать за пределами потребителя.)
Есть несколько способов сделать это, и они показаны в коде ниже (комментарии объясняют):
class Program
{
static void Main(string[] args)
{
//ACTUAL usage
//Setting up the interface injection
IInjectableFactory.StaticInjectable = new ConcreteInjectable(1);
//Injecting via the constructor
EverythingsInjected injected =
new EverythingsInjected(new ConcreteInjectable(100));
//Injecting via the property
injected.PropertyInjected = new ConcreteInjectable(1000);
//using the injected items
injected.PrintInjectables();
Console.WriteLine();
//FOR TESTING (normally done in a unit testing framework)
IInjectableFactory.StaticInjectable = new TestInjectable();
EverythingsInjected testInjected =
new EverythingsInjected(new TestInjectable());
testInjected.PropertyInjected = new TestInjectable();
//this would be an assert of some kind
testInjected.PrintInjectables();
Console.Read();
}
//the inteface you want to represent the decoupled class
public interface IInjectable { void DoSomething(string myStr); }
//the "real" injectable
public class ConcreteInjectable : IInjectable
{
private int _myId;
public ConcreteInjectable(int myId) { _myId = myId; }
public void DoSomething(string myStr)
{
Console.WriteLine("Id:{0} Data:{1}", _myId, myStr);
}
}
//the place to get the IInjectable (not in consuming class)
public static class IInjectableFactory
{
public static IInjectable StaticInjectable { get; set; }
}
//the consuming class - with three types of injection used
public class EverythingsInjected
{
private IInjectable _interfaceInjected;
private IInjectable _constructorInjected;
private IInjectable _propertyInjected;
//property allows the setting of a different injectable
public IInjectable PropertyInjected
{
get { return _propertyInjected; }
set { _propertyInjected = value; }
}
//constructor requires the loosely coupled injectable
public EverythingsInjected(IInjectable constructorInjected)
{
//have to set the default with property injected
_propertyInjected = GetIInjectable();
//retain the constructor injected injectable
_constructorInjected = constructorInjected;
//using basic interface injection
_interfaceInjected = GetIInjectable();
}
//retrieves the loosely coupled injectable
private IInjectable GetIInjectable()
{
return IInjectableFactory.StaticInjectable;
}
//method that consumes the injectables
public void PrintInjectables()
{
_interfaceInjected.DoSomething("Interface Injected");
_constructorInjected.DoSomething("Constructor Injected");
_propertyInjected.DoSomething("PropertyInjected");
}
}
//the "fake" injectable
public class TestInjectable : IInjectable
{
public void DoSomething(string myStr)
{
Console.WriteLine("Id:{0} Data:{1}", -10000, myStr + " For TEST");
}
}
Выше приведена полная консольная программа, которую вы можете запустить и поиграть, чтобы увидеть, как это работает. Я старался быть проще, но не стесняйтесь задавать мне любые ваши вопросы.
Второе редактирование:
Из комментариев стало ясно, что это оперативная необходимость, а не необходимость тестирования, поэтому по сути это был кэш. Вот код, который будет работать по назначению. Опять же, приведенный ниже код представляет собой полнофункциональную консольную программу.
class Program
{
static void Main(string[] args)
{
ServiceFactory factory = new ServiceFactory(false);
//first call hits the webservice
GetServiceQuestions(factory);
//hists the cache next time
GetServiceQuestions(factory);
//can refresh on demand
factory.ResetCache = true;
GetServiceQuestions(factory);
Console.Read();
}
//where the call to the "service" happens
private static List<Question> GetServiceQuestions(ServiceFactory factory)
{
var myFirstService = factory.GetSATService();
var firstServiceQuestions = myFirstService.GetAllQuestions();
foreach (Question question in firstServiceQuestions)
{
Console.WriteLine(question.Text);
}
return firstServiceQuestions;
}
}
//this stands in place of your xml file
public static class DataStore
{
public static List<Question> Questions;
}
//a simple question
public struct Question
{
private string _text;
public string Text { get { return _text; } }
public Question(string text)
{
_text = text;
}
}
//the contract for the real and fake "service"
public interface ISATService
{
List<Question> GetAllQuestions();
}
//hits the webservice and refreshes the store
public class ServiceWrapper : ISATService
{
public List<Question> GetAllQuestions()
{
Console.WriteLine("From WebService");
//this would be your webservice call
DataStore.Questions = new List<Question>()
{
new Question("How do you do?"),
new Question("How is the weather?")
};
//always return from your local datastore
return DataStore.Questions;
}
}
//accesses the data store for the questions
public class FakeService : ISATService
{
public List<Question> GetAllQuestions()
{
Console.WriteLine("From Fake Service (cache):");
return DataStore.Questions;
}
}
//The object that decides on using the cache or not
public class ServiceFactory
{
public bool ResetCache{ get; set;}
public ServiceFactory(bool resetCache)
{
ResetCache = resetCache;
}
public ISATService GetSATService()
{
if (DataStore.Questions == null || ResetCache)
return new ServiceWrapper();
else
return new FakeService();
}
}
Надеюсь, это поможет. Удачи!