Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Suppose a FileWriter class that needs validation that it will not erase a file already present, if one is found. It would have two functions:

public bool FileExists(string filePath) //...
public bool WriteFile(string filePath, string text) //...

The main concern is to not erase a file already present. A first interface is actually just interaction via a console:

public void Save()
{
    FileWriter fileWriter;
    //...
    if (fileWriter.FileExists(filePath))
    {
        Console.WriteLine("File already exists. Continue? Press 'y' for yes");
        if (Console.ReadKey().KeyChar != 'y')
            return;
    }
    fileWriter.WriteFile(filePath, text);
}

And some time later comes a second interface, this one with a GUI, that needs the same user interaction:

public void SaveButton_click(object sender, EventArgs e)
{
    FileWriter fileWriter;
    //...
    if (fileWriter.FileExists(filePath))
    {
        if (DialogResult.Yes != MessageBox.Show("File already exists. Continue?", "", MessageBoxButtons.YesNo))
            return;
    }
    fileWriter.WriteFile(filePath, text);
}

Save for the way the interaction is made, the logic is the same. What pattern can be used to not duplicate this logic? Is a callback function to perform the check the best approach?

Formatted as C#, but doesn't have to be C# specific.

share|improve this question
add comment

2 Answers

up vote 1 down vote accepted

I don't know if it's a pattern wih a name, but this is a nice way to solve it:

interface IUserInputService
{
  bool AskQuestion( string q );
}

class FileWriterService
{
  public FileWriterService( IUserInputService scv )
  {
    this.svc = svc
  }

  public void WriteFileIfItDoesntExist( string path, string text )
  {
    FileWriter fileWriter;
    if( fileWriter.FileExists( path ) )
      if( !svc.AskQuestion( "File exists, continue?" ) )
        return;
    fileWriter.WriteFile( path, text );
  }
}

then you provide implementations of the input service dependinh on whether you're on a console or want a dialog/popup/...

share|improve this answer
add comment

If you have a business logic class (in this case your FileWriter) that needs to bring up some UI (the dialog or console input in your case) one should separate this UI from the business logic. You didn't describe it in these terms, but I think your question goes into that direction.

In that case your FileWriter would only expose the one method WriteFile() and would check internally, whether the file exists. If it does, it would call a delegate (e.g. a callback passed into the WriteFile() method) to ask for permission to overwrite it. This way all your business logic (checking file existance, writing the file, etc.) is encapsulated in the FileWriter class and the code calling from the UI would provide the means to ask for confirmation.

If there are additional situations where FileWriter might need to call back to the code invoking it, having individual delegates for each of these situations might be a bit messy. If the situations are all very similar, you might provide additional information about them in the event args to the delegate. Or the user could pass in an interface (say IConfirmationProvider) whose methods the FileWriter could call to ask for confirmation in each of the different situations. Really depends on the exact nature of the situations where permission is needed.

share|improve this answer
    
you are all right about the seperation, but I would take it one step further: I don't think FileWriter itself should have to know about callbacks/delegates. A method 'WriteFile' just should write a file, mothing more and nothing less. Putting the logic whether or not to write the file inside FileWriter itself feels wrong. –  stijn Dec 22 '11 at 8:23
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.