2

Let's suppose I need to save a text in my application into a file, but allowing the user to have more than one format (.pdf, .word, .txt, ...) to select.

A first approach could be:

if (extension == ".pdf")
  ExportToPdf(file);
else if (extension == ".txt")
  ExportToTxt(file);
...

but I usually encapsulate the above like this:

abstract class Writer
{
  abstract bool CanWriteTo(string file);
  abstract void Write(string text, string file);
}

class WritersHandler
{
  List<Writer> _writers = ... //All writers here

  public void Write(string text, string file) 
  {
    foreach (var writer in _writers) 
    {
      if (writer.CanWriteTo(file) 
      {
        writer.Write(text, file);
        return;
      {
    }
    throw new Exception("...");
  }
}

Using it, if I need to add a new extension/format, all I have to do is create a new class (that inherits from Writer) for that writer and implement the CanWriteTo(..) and Write(..) methods, and add that new writer to the list of writers in WritersHandler (maybe adding a method Add(Writer w) or manually, but that's not the point now).

I also use this in other situations.

My question is:

What's the name of this pattern? (maybe it's a modification of a pattern, don't know).

Oscar Mederos
  • 29,016
  • 22
  • 84
  • 124

2 Answers2

5

It's the Chain Of Responsibility.
It basically defines a chain of processing objects, where the supplied command is passed to the next processing object if the current one can't handle it.

Botz3000
  • 39,020
  • 8
  • 103
  • 127
  • Thank you very much for your answer. It seems to be that pattern, but just a modified version (instead of having some kind of a linked list of objects, *someone* has a list that contains all of them). Do you think I should use it as I'm using it now, or use the original pattern (with sucessor, etc)? Maybe I should post it as a new question here. – Oscar Mederos Feb 16 '11 at 19:09
  • I think it's the perfect pattern for this kind of operations. I also think i can remember that handling of different file types is one of the examples commonly used for this pattern. It's fine as you're using it. for discovering your file handlers, there are some patterns, too, but that's another topic. – Botz3000 Feb 16 '11 at 20:09
  • 1
    It is not really CainOfResponsibility. It is only accidently coded as an if else chain. If he had used a dictionary to select the handler from the file extension, then there was no chain ;D So: the core of his design is the fact that the writing of a specific file format is isolated into a WritersHandler class. And that is: Strategy ;D So ... even if he puts a test in a chain in front of it, it is still not chain of command. As in CoC the WritersHandler would decide if he can write, and if not _he_ would call its next one in the chain. In a CoC pattern ... – Angel O'Sphere Jun 03 '11 at 12:26
  • ... you don't know from the outside that there is a chain. – Angel O'Sphere Jun 03 '11 at 12:26
1

I would do it a bit differently than you.

The main difference would be the way of storing handlers and picking the right one. In fact I think that chain of responsibility is a bad choice here. Moreover iterating through the ist of handlers may be time consuming (if there are more of them). Dictionary provides O(1) writer retrieval. If I were to guess I'd tell that my pattern is called Strategy.

abstract class Writer
{
  abstract string SupportedExtension {get;}
  abstract void Write(string text, string file);
}

class WritersHandler
{
  Dictionary<string,Writer> _writersByExtension = ... //All writers here

  public void Init(IEnumerable<Writer> writers)
  {
     foreach ( var writer in writers )
     {
        _writersByExtension.Add( writer.SupportedExtension, writer );
     }
  }

  public void Write(string text, string file) 
  {
    Writer w = _writersByExtension.TryGetValue( GetExtension(file) );
    if (w == null)
    {
       throw new Exception("...");
    }
    w.Write(text, file);
  }
}
dzendras
  • 4,721
  • 1
  • 25
  • 20
  • You're right. It seems more the Strategy pattern than the Chain of Responsibility (although the design isn't exactly the same). [Here](http://c2.com/cgi/wiki?StrategyPattern) *Ralph Johnson* says: "A strategy is either selected by an outside agent or by the context". In this case, the 'strategy' to be used is selected by the context. – Oscar Mederos Feb 18 '11 at 08:09