views:

102

answers:

3

I have an abstract Catalog class as follows. It has a static method OpenCatalog() which is used to return a specific concrete catalog based on the type of location provided. Once it has determined the type of catalog it then calls a specific OpenCatalog() method of the correct concrete catalog type. For example I may have an implementation of Catalog that is stored in a SQL database, or another which is stored in a file system. See the code below.

public abstract class Catalog
{
    public static ICatalog OpenCatalog(string location, bool openReadOnly)
    {

        if(location is filePath)
        {
            return FileSystemCatalog.OpenCatalog(string location, bool openReadOnly);
        }
        else if(location is SQL server)
        {
            return SqlCatalog.OpenCatalog(string location, bool openReadOnly);
        }
        else
        {
            throw new ArgumentException("Unknown catalog type","location");
        }
    }

    ...

}

public abstract class FileSystemCatalog:Catalog
{

    public static new ICatalog OpenCatalog(string location, bool openReadOnly)
    {
        //Deserializes and returns a catalog from the file system at the specified location
    }

    ...

}



public abstract class SqlCatalog:Catalog
{

    public static new ICatalog OpenCatalog(string location, bool openReadOnly)
    {
        //creates an returns an instances of a SqlCatalog linked to a database
        //at the provided location          
    }

    ...

}

First in general is it ok to hide a static method? I know it's possible to do, but it also just seems like something that one shouldn't do very often. Also is this a valid example where it's ok to hide a static method, or is there a better way to do what I'm trying to do?

A: 

I have never found an argument against the use of private/internal static methods in terms of "code smell".

A good practical example might be an extension method inside some sort of service/utility library that you want to only extend within that library.

internal static ShippingRateType ToShippingRateType(this ProviderShippingRateType rateType) { }
Nathan Taylor
A: 

You aren't really hiding it because you can always do

Catalog.OpenCatalog(...);

If you want the base class version. In fact, static methods are associated with a specific class and aren't virtual. It's just a nice convenience that you can call static methods defined in a base class on the derived class.

siride
+2  A: 

It looks like you are trying to create an abstract factory in a very awkward manner. What actually happens is you are violationg Single Responsibility Principle and mixing the catalog creation concern with the catalog concern. What you need to do is to make CatalogFactory non-static class. This gives you the flexibility to whatever you please later on (eg Dependency Injection).

public class CatalogFactory {
  public ICatalog CreateCatalog(string location, bool openReadOnly)
  {

    if(location is filePath)
    {
        return OpenFileCatalog(string location, bool openReadOnly);
    }
    else if(location is SQL server)
    {
        return OpenSqlCatalog(string location, bool openReadOnly);
    }
    else
    {
        throw new ArgumentException("Unknown catalog type","location");
    }
  }
  FileSystemCatalog OpenFileCatalog(string location, bool openReadOnly) {
    return new FileSystemCatalog{/*init*/};
  }
  SqlCatalog OpenSqlCatalog(string location, bool openReadOnly) {
    return new SqlCatalog{/*init*/};
  }

}
Igor Zevaka
Ok I get it. Although I will not always call the constructor of each concrete catalog type directly. For example when my FileSystemCatalog is opened it is deserialized from an XML file through DataContractSerializer. It is really DataContractSerializer that calls the constructor. So I need a static method somewhere where I can instantiate aDataContractSerializer and use it to attempt to deserialize a Catalog from a file.
Eric Anastas
Yeah, that's OK, I just put `new FileSystemCatalog` for illustration sake. Also, not that this method is in a class other than `Catalog`, the method does not need to be static, hence it can be mocked in a unit test.
Igor Zevaka