There's a school of thought associated with Domain-Driven Design that holds that Domain Objects should be POCOs/POJOs, so according to that philosophy the Sandwich class should be independent of the IMeatGetter and IVeggiesGetter services. I personally find that this approach works well despite certain drawbacks.
If the total lists of veggies and meats make sense in the context of a Sandwich (it sounds more like a potential sandwich to me, though), I would pass them in as part of the constructor. Here's a C# example:
public class Sandwich
{
private readonly IEnumerable<Ingredient> veggies;
private readonly IEnumerable<Ingredient> meats;
public Sandwich(IEnumerable<Ingredient> veggies, IEnumerable<Ingredient> meats)
{
if(veggies == null)
{
throw new ArgumentNullException("veggies");
}
if(meats == null)
{
throw new ArgumentNullException("meats");
}
this.veggies = veggies;
this.meats = meats;
}
// implement GetToppings as described in OP
}
If IMeatGetter is used to retrieve the list of meats and that is a very slow operation, then no, that would not change my answer. In this way we have decoupled the Sandwich class from the retrieval logic of the meats.
This allows us to attempt to manage the lifetime of the meats list elsewhere. We might, for example, write an implementation of IMeatGetter that caches the list of meats in memory.
Even if that's not possible, we can still change the list itself to do a lazy evaluation. Although I don't know which platform you are using, in .NET, the IEnumerable<T>
interface allows deferred execution; in other words, it doesn't retrieve the list until you actually begin the enumeration.
If you are working on a different platform, it should still be trivial to introduce a custom interface that enables lazy loading of the meats.
In summary, you pass a reference to a list into the Sandwich class. That list may or may not be loaded into memory at that time, but that's up to you to control - independently of the Sandwich class. Thus, the Sandwich class conforms to the Single Responsibility Principle because it doesn't have to deal with managing the lifetime of meats.