Thank you for the detailed response. Examples are definitely helpful! :)
I think what you’ve done is fine since it’s basically a functional approach that avoids the explosion of traditional factory classes. My only suggestion is to use Func<IAnimal> instead of a delegate. The modern syntax is easier to read and work with, IMHO.
Func are nameless. Making arguably "harder" to understand when you find it in the code. Creating a delegate allows you to name it and make easier to "inject" it using DI. And having a name also expresses what you intend to do with that function.
The delegate is definitely a bit old school, but for purposes of illustration, I felt the explicit signature lent some clarity to what I was trying to communicate. In real-world code, a Func<T> might very well be preferable.
As I commented elsewhere, factories which only wrap a new are good for demonstrating "Here's how a factory works," but don't provide much other value. Having a separate factory for each class, particularly when they're just "wrap the new", is something to avoid; I'm tempted to call it an anti-pattern.
I suspect there's something similar at play here with the description of factory methods. I understand how to write them, you've communicated that pretty darn well. But I'm struggling with the compelling reason why they're preferable to well-designed factory classes.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.