Re: MVP's: static methods in interfaces. (REDEFINED)

Tech-Archive recommends: Fix windows errors by optimizing your registry

From: Nick Malik [Microsoft] (nickmalik_at_hotmail.nospam.com)
Date: 12/22/04


Date: Wed, 22 Dec 2004 08:28:45 GMT

Hello Dan,

> How would you approach the following:
>
> In developing an application, it becomes obvious that a few lines of code
is
> being repeated more than a few times and so refactoring is to be done. The
> thing is it's not necessarily object specific, but more of a general set
of
> commands.

I would start with the question: what is similar between each case, and what
varies. The things that are similar should be pushed toward the top of the
inheritance tree, while the things that vary should be encapsulated. (This
is a short-hand definition of "commonality variability analysis" or CVA.
Refer to [Coplien] and [Shalloway]).

On the surface, if there is a set of repeating statements within a set of
related classes, I would think "strategy pattern" and that's where the
paragraph above led me... until I read the next part...

> This is referenced all over applications, across different projects in my
> solution (which means it's in a constants / enum definitions / type class
> library) every time an exception of any sort is thrown for logging
purposes.

well... the strategy pattern appears to go right out the window. After all,
the repeating code is not part of related classes! So I start to think
about what you are trying to accomplish.

You defined a static method (some would call it a "helper" method) that
takes an exception object and returns a string suitable for throwing to a
log file or an exception handler of some kind.

Clearly, the thing that varies is this: what will we do with this string?
The thing that is constant is: we need a uniform description of the
exception that contains an inordinately large amount of information. :-)
So, the creation of this string is at the top, perhaps as a concrete method
in an abstract class. The classes that inherit from that abstract class
will use this method by the fact that it is defined in the base class. The
inherited members will decide how to log the error.

So, it would look something like this:

// caveat: air code. I didn't compile this. Please forgive typos.

public abstract class IExceptionClass
{
   private string ExceptionInfo ( Exception ex )
  {
     if ( ex == null ) return "";

     StringBuilder sb = new StringBuilder();
     sb.Append( " Exception: " );
     sb.Append( ex.Message );
     sb.Append("\r\n");
     sb.Append( " Stack Trace: ");
     sb.Append( ex.StackTrace );
     return sb.ToString();
  }
  public void LogThisEvent(Exception ex)
  {
      string DisplayString = ExceptionInfo(ex);
      WriteEventToLog(DisplayString);
  }

  private abstract void WriteEventToLog(string DisplayString);

}

Now, I am assuming that, since your static method didn't actually DO
anything with the string, that you will want to do many things with the
string, depending on what your code is up to. In that case, each of those
many things would require you to create a class like so:

public class MyTracer : IExceptionClass
{
    private override void WriteEventToLog(string DisplayString)
    {
         // -- code goes here to write the event to a trace log.
    }
}

public class MyEventLogger : IExceptionClass
{
    private override void WriteEventToLog(string DisplayString)
    {
         // -- code goes here to write the event to the event log
    }
}

and so on.

Add in a method in our handy-dandy class factory:
public class MyClassFactory : IMyAbstractFactory
{
   /// ... singleton declaration and Instance property
   /// ... other factory methods
   public IExceptionClass GetEventLogger()
   {
      return new MyEventLogger();
   }
}

In your code, when an event occurs, you would do this:
// snippet
   // note: In this example, I will use a singleton to control the creation
of the class factory

   try {
       // offending, but not offensive, code
   } catch (Exception ex) // for the sake of simplicity
   {
      MyEventLogger el = MyClassFactory.Instance.GetEventLogger();
      el.LogThisEvent(ex);
   }

You are no longer calling a static method. On the other hand, you do not
have to define the code more than once. The code is part of the handling of
errors. It is cohesively correct to place it in the inheritance tree for
the handling of errors.

Interestingly enough, the way this ends up being implemented... it's a
strategy pattern after all.
Alas, a good idea is hard to kill.

-- 
--- Nick Malik [Microsoft]
    MCSD, CFPS, Certified Scrummaster
    http://blogs.msdn.com/nickmalik
Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
   I do not answer questions on behalf of my employer.  I'm just a
programmer helping programmers.
--


Relevant Pages

  • Xml Serialization, properties and new
    ... I'm getting the following exception in certain situations when using the Xml Serializer to serialize a class that has changed the type of a property defined on its base class by using the 'new' keyword. ... Member class2.prop of type XmlSerializerNewTest.inner2 hides base class member class1.prop of type XmlSerializerNewTest.inner1. ... at System.Xml.Serialization.StructMapping.FindDeclaringMapping(MemberMapping member, StructMapping& declaringMapping, String parent) ... public class Class2 ...
    (microsoft.public.dotnet.xml)
  • hashtable add fails unexpectedly when using attribute instances as keys
    ... adding them both as keys in a hashtable will throw an exception. ... Public Class TestAttribute ... Public Sub New(ByVal ifoo As String) ...
    (microsoft.public.dotnet.languages.vb)
  • RE: Detailed ASP.Net info not displaying in browser
    ... HTTP 500 page when an exception is thrown from the web service. ... at VOSE.Data.DataRequest.dr_DB2Process.DeleteCommRows(String company, String ... objQueue, tOrderManagementIndicator omindicator, Int32 intTriggerId) in ... Microsoft Online Community Support ...
    (microsoft.public.dotnet.xml)
  • RE: Detailed ASP.Net info not displaying in browser
    ... HTTP 500 page when an exception is thrown from the web service. ... at VOSE.Data.DataRequest.dr_DB2Process.DeleteCommRows(String company, String ... objQueue, tOrderManagementIndicator omindicator, Int32 intTriggerId) in ... Microsoft Online Community Support ...
    (microsoft.public.dotnet.xml)
  • Re: App_data - ASPNETDB.MDF
    ... is only because I want my site work, without exception. ... Server Error in '/' Application. ... serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, Int64 ...
    (microsoft.public.dotnet.framework.aspnet)