[ProgClub list] What is IoC?
Stuart Laughlin
stuart at bistrotech.net
Tue Oct 11 07:14:03 AEDT 2011
Found a bug in Notifier.NotifySenders(). The 'this.' obviously
shouldn't be there. Therefore, the Notifier class should look like
this:
public class Notifier {
public void NotifyUsers(IEnumerable<User> users, string message) {
var sender = new EmailSender();
foreach (var user in users) {
sender.Send(message, user);
}
}
}
--Stuart
On Mon, Oct 10, 2011 at 11:57 AM, Stuart Laughlin <stuart at bistrotech.net> wrote:
> I intend to explain this over a few small bursts. I'm writing quickly
> with minimal editing (and frankly I didn't even make sure my code
> compiles) so apologies in advance for any wonkiness.
> Interaction/comments are welcome.
>
> ~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_
>
> There are a lot of good articles on the web that attempt to explain
> Inversion of Control [1]. This is my humble attempt. My audience is
> primarily John Elliot, but maybe you'll find this helpful, too. All
> code examples will be in C#.
>
> First things first. As you have no doubt already perceived, IoC stands
> for "Inversion of Control." Inversion of Control is not a technology
> but rather a principle of software development that advocates
> reversing the control structure commonly found in traditional software
> design. Traditionally, a class instance creates the other components
> on which it relies to do its work. Consider the following example code
> (which is contrived but I think fairly representative), paying close
> attention to the relationship between the Notifier class and the
> EmailSender class.
>
> public class EmailSender {
> public void Send(string message, User user) {
> string host = getHostFromConfig();
>
> /* send email using SmtpClient or similar */
> ...
> }
> }
>
> public class Notifier {
> public void NotifyUsers(IEnumerable<User> users, string message) {
> var sender = new EmailSender();
>
> foreach (var user in users) {
> this.sender.Send(message, user);
> }
> }
> }
>
> public class MainClass {
> public static void Main(string[] args) {
> var process = new SomeProcess();
> var result = process.Run();
>
> var admins = new List<User> {
> new User {'sclaughl'},
> new User {'jj5'}
> }
>
> var notifier = new Notifier();
> notifer.NotifyUsers(admins, result);
> }
> }
>
> First observe the Notifier class. The Notifier class depends upon the
> EmailSender class to do the heavy lifting; therefore it instantiates
> an object of type EmailSender directly. This approach has several
> ramifications. First, the Notifier class potentially has a very
> demanding dependency chain. It requires a reference to the assembly
> containing EmailSender, as well as any/all assemblies referenced by
> EmailSender (e.g. System.dll which contains
> System.Net.Mail.SmtpClient) and their dependencies, all the way down
> the line. In this simple example it may not cause much of an issue,
> but it's not difficult to imagine deep and complicated dependency
> chains resulting from this approach. Second, Notifier is not
> polymorphic. It can notify users via email and by no other means.
> Ideally we would like our Notifier to be able to use other means of
> notification as well, perhaps via SMS, log file, or console output.
> Finally, the combined effect of these issues is that too much control
> is taken away from our Main method. Since our Main method is the entry
> point and primary controlling mechanism of this simple application, we
> would like it to maintain as much decision-making power as possible.
> As we develop the classes that compose our system, we want to remain
> as abstract as possible, thereby deferring as much control and
> behavior as possible, pushing those decisions out to the edge of the
> system where they can be specified by the concrete application.
>
> Also observe the EmailSender class. The EmailSender requires a 'host'
> setting in order to relay the email. Traditionally we might store this
> setting in an application configuration file. While this approach
> gives the desired flexibility, it ties the class to a configuration
> file and makes unit testing more convoluted. Ideally the EmailSender
> would simply rely on a 'host' variable being set, thereby giving us
> the flexibility of providing the setting however we see fit,
> configuration file or otherwise.
>
>
> 1: My favorite at the moment is by Martin Fowler at
> http://www.martinfowler.com/articles/injection.html.
>
> ~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~
>
> Next time we'll work on fixing some of these problems by applying the
> principles of IoC.
>
>
> --Stuart
>
More information about the list
mailing list