А также указатели и ссылки на неполные типы, можно также объявить прототипов функции, которые указывают параметры и/или возвращаемые значения, которые являются неполными типами. Однако Вы не можете определять функция, имеющая параметр или тип возврата, который является неполным, если это не указатель или ссылка.
Примеры:
struct X; // Forward declaration of X
void f1(X* px) {} // Legal: can always use a pointer
void f2(X& x) {} // Legal: can always use a reference
X f3(int); // Legal: return value in function prototype
void f4(X); // Legal: parameter in function prototype
void f5(X) {} // ILLEGAL: *definitions* require complete types
Оба подхода плохи тем, что из контракта класса не очевидно, каковы его зависимости. То есть в
private void foo()
{
var x = SomeSingleton.Instance.GetX();
var y = ServiceLocator.GetService<IProvider>().GetY();
}
есть ссылки на SomeSingleton
и IProvider
, спрятанные глубоко где-то внутри.
Однако, по сравнению с чисто одноэлементным подходом, локаторы сервисов обычно намного лучше, поскольку они позволяют для более простой централизованной конфигурации, управления сроком службы и т. д. Они также обеспечивают лучшую тестируемость (вы всегда можете имитировать вызовы GetService
), более низкую связь, разделение задач и т. д.