Isso visa ser uma resposta complementar ao Doc Brown e também responder a comentários não respondidos de Dinaiz que ainda estão relacionados à Questão.
O que você provavelmente precisa é de uma estrutura para executar DI. Ter hierarquias complexas não significa necessariamente um design ruim, mas se você precisar injetar um TimeFactory de baixo para cima (de A a D) em vez de injetar diretamente em D, provavelmente há algo errado com o modo como você está injetando dependências.
Um singleton? Não, obrigado. Se você precisar de apenas uma instância para compartilhá-lo no contexto de seu aplicativo (o uso de um contêiner de IoC para DI, como o Infector ++, requer apenas a ligação do TimeFactory como uma única instância), eis o exemplo (C ++ 11, a propósito, mas C ++.) para C ++ 11? Você obtém o aplicativo Leak-Free gratuitamente):
Infector::Container ioc; //your app's context
ioc.bindSingleAsNothing<TimeFactory>(); //declare TimeFactory to be shared
ioc.wire<TimeFactory>(); //wire its constructor
// if you want to be sure TimeFactory is created at startup just request it
// (else it will be created lazily only when needed)
auto myTimeFactory = ioc.buildSingle<TimeFactory>();
Agora, o ponto positivo de um contêiner de IoC é que você não precisa passar o time factory até D.
ioc.bindAsNothing<A>(); //declare class A
ioc.bindAsNothing<B>(); //declare class B
ioc.bindAsNothing<D>(); //declare class D
//constructors setup
ioc.wire<D, TimeFactory>(); //time factory injected to class D
ioc.wire<B, D>(); //class D injected to class B
ioc.wire<A, B>(); //class B injected to class A
quando você injeta o TimeFactory apenas uma vez. Como usar "A"? Muito simples, todas as classes são injetadas, construídas em geral ou com uma fábrica.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
toda vez que você criar a classe A, ela será automaticamente injetada (atenuação lenta) com todas as dependências até D e D serão injetadas com TimeFactory, portanto, chamando apenas 1 método, você terá sua hierarquia completa pronta (e até hierarquias complexas são resolvidas dessa maneira) removendo MUITO código da placa da caldeira): Você não precisa chamar "novo / excluir" e isso é muito importante porque é possível separar a lógica do aplicativo do código da cola.
D pode criar objetos Time com informações que apenas D pode ter
Isso é fácil, o TimeFactory possui um método "create", basta usar uma assinatura diferente "create (params)" e pronto. Parâmetros que não são dependências geralmente são resolvidos dessa maneira. Isso também remove o dever de injetar coisas como "strings" ou "inteiros", porque isso apenas adiciona uma placa de caldeira extra.
Quem cria quem? O contêiner de IoC cria instâncias e fábricas, as fábricas criam o restante (fábricas podem criar objetos diferentes com parâmetros arbitrários, para que você realmente não precise de um estado para fábricas). Você ainda pode usar as fábricas como invólucros para o contêiner de IoC: geralmente o Injectin no contêiner de IoC é muito ruim e é o mesmo que usar um localizador de serviço. Algumas pessoas resolveram o problema envolvendo o Container IoC com uma fábrica (isso não é estritamente necessário, mas tem a vantagem de que a hierarquia é resolvida pelo Container e todas as suas fábricas ficam ainda mais fáceis de manter).
//factory method
std::unique_ptr<myType> create(params){
auto istance = ioc->build<myType>(); //this code's agnostic to "myType" hierarchy
istance->setParams(params); //the customization you needed
return std::move(istance);
}
Além disso, não abuse da injeção de dependência, tipos simples podem ser apenas membros da classe ou variáveis de escopo local. Isso parece óbvio, mas vi pessoas injetando "std :: vector" apenas porque havia uma estrutura de DI que permitia isso. Lembre-se sempre da lei de Deméter: "Injete apenas o que você realmente precisa injetar"