Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
It makes no sense to me why C# doesn't support static methods & static properties in interfaces. In a brief survey of other SO questions on the issue, I come across a variety of answers ranging from "it's apparently an oversight in the design of C# and/or the CLR, and fixing it would break existing code" all the way to "interfaces are meant to interact with objects, and if you find yourself wanting to use interfaces otherwise, you're obviously lacking grey matter and should probably go back to sweeping floors". This question exhibits the full range of such answers.
I need a family of parsers, each with a method that determines if the assembly file contents passed to it matches its platform type. These are stateless entities; there's no reason to have "objects" of these parsers other than that C# interfaces require class instances. If I rip out all the "static" keywords below, this code compiles without error.
public interface IParser
{
static string platformName { get; }
static bool isThisPlatform(string asmFileContents);
static bool parseAsm(string asmFileContents);
}
class PIC32MX_GCC_Parser : IParser
{
public static string platformName { get { return "PIC32MX_GCC"; } }
public static bool isThisPlatform(string asmFileContents)
{
return false; // stub
}
public static bool parseAsm(string asmFileContents)
{
return false; // stub
}
}
class M16C_IAR_Parser : IParser
{
public static string platformName { get { return "M16C_IAR"; } }
public static bool isThisPlatform(string asmFileContents)
{
return false; // stub
}
public static bool parseAsm(string asmFileContents)
{
return false; // stub
}
}
IParser[] parsers =
{
new PIC32MX_GCC_Parser(),
new M16C_IAR_Parser()
};
public IParser findTheRightParser(string asmFileContents)
{
foreach(IParser parser in parsers)
{
if (parser.isThisPlatform(asmFileContents))
{
Console.WriteLine("Using parser: ", parser.platformName);
return parser;
}
}
return null;
}
I'd like to ask why C# won't let me do this, but I know the answer is just "because it doesn't." I know the "workaround" is to just implement them as instance methods which, if necessary, call a static method (which isn't actually necessary in this case).
Since there are a number of people out there (many with high SO rep) who think that putting static methods in interfaces makes no logical sense and if you want to do so there's something wrong with your design, or your head (or both), I'd like some of those people to help me out & give me a good, simple alternative to my code above which uses static methods and doesn't simply "work around" the issue by having instance methods wrap static methods.
There is a need for objects because what you appear to be looking for is dynamic dispatch- you want to be able to call a method on an interface (IParser.Parse), but have the implementation of the method defined by the concrete implementation of the interface. This is classic OOP, and C# (as well as Java) only supports it via instance methods. Singletons eliminate the need for an allocation per call, so that's a good approach. Alternatively you cal use static classes and static methods- but then you are limited to static dispatch, because the caller must know which implementation to call.
In short- it isn't a C# limitation. It's a limitation of most if not all object oriented programming languages.
There are many examples of singleton implementations in the C# literature (for example: http://www.dotnetperls.com/singleton).
To come up with other alternatives requires changing the way that you select your parser. For example, if you wanted to select it via an enum:
enum ParserType {
PIC32MX_GCC,
M16C_IAR,
Other_Parser,
}
Then something like this will work:
public static bool parseAsm(ParserType type, string asmFileContents) {
switch type {
case PIC32MX_GCC:
return PIC32MX_GCC_Parser.ParseAsm(asmFileContents);
case M16C_IAR:
return M16C_IAR_Parser.ParseAsm(asmFileContents);
default:
throw new NotImplementedException("I dont know this parser type");
}
}
You can also do what you are already trying to do, via reflection (but the performance will be very bad):
Type[] parsers =
{
typeof(PIC32MX_GCC_Parser),
typeof(M16C_IAR_Parser)
};
public Type findTheRightParser(string asmFileContents)
{
foreach(Type parser in parsers)
{
// You probably want to cache this
var mi = parser.GetMethod("isThisPlatform", BindingFlags.Static);
if ((Boolean)mi.Invoke(null, new object[] {asmFileContents}))
{
Console.WriteLine("Using parser: ", parser.platformName);
return parser;
}
}
return null;
}
You can't have static interfaces but you can get the behavior you are looking for if you switch to singletons that redirect to the static fields. Because you use a singleton and the singleton holds no data it has a very low memory overhead, only a few bytes per type.
public interface IParser
{
string platformName { get; }
bool isThisPlatform(string asmFileContents);
bool parseAsm(string asmFileContents);
}
class PIC32MX_GCC_Parser : IParser
{
private PIC32MX_GCC_Parser()
{
}
public static string platformName { get { return "PIC32MX_GCC"; } }
public static bool isThisPlatform(string asmFileContents)
{
return false; // stub
}
public static bool parseAsm(string asmFileContents)
{
return false; // stub
}
private static readonly PIC32MX_GCC_Parser _instance = new PIC32MX_GCC_Parser();
public static IParser Instance
{
get { return _instance; }
}
string IParser.platformName { get { return platformName; } }
bool IParser.isThisPlatform(string asmFileContents)
{
return isThisPlatform(asmFileContents);
}
bool IParser.parseAsm(string asmFileContents)
{
return parseAsm(asmFileContents);
}
}
class M16C_IAR_Parser : IParser
{
//..snip
}
Parser[] parsers =
{
PIC32MX_GCC_Parser.Instance,
M16C_IAR_Parser.Instance
};
public IParser findTheRightParser(string asmFileContents)
{
foreach (IParser parser in parsers)
{
if (parser.isThisPlatform(asmFileContents))
{
Console.WriteLine("Using parser: ", parser.platformName);
return parser;
}
}
return null;
}
However if this where me I would just drop the static methods and put all of the data right inside the singleton.
Related
I'd like to know if there is a design pattern for this problem:
One input is used to construct an object (via constructor or via method return I don't care), that object is feed to the next method or constructor. This is repeated on a user specified set of processors, obviously throwing exceptions if there is a break in the chain of required inputs for the processors.
The output of all, some or none of the implemented processors is the same object.
I've got about 6 processors planned, possibly more in future.
Composition:
I'm not sure I like the composition design pattern because not every object is intended to be an output of this process and I can't think how to not output null values without the user knowing it's going to be null.
Chain of responsibility:
Chain of responsibility is the way to go according to what I've heard however I'm not sure i understand it. Is this design pattern suggesting to pass n function pointers to a function that runs through each? If so, I'm not sure how to setup the function that gets passed n function pointers.
my attempt:
I've got two interface that are inherited by n classes ie (FirstProcessor, FirstInput, FirstOutput, SecondProcessor, SecondOutput, ThirdProcessor,.., NProcessor, NOutput)
IChainedOutput
{
IChainedOutput Input {get;}
FinalOutputOBj GetFinalOutput()
}
IChainedProcessor
{
IChainedOutput Run(IChainedOutput previousOutput)
}
used like this:
IChainedProcessor previous = FirstProcessor(originalInput)
foreach(IChainedProcessor processor in processorList.Skip(1)
{
IChainedOutput current = processor.Run(previous)
previous = current;
}
FinalOutputObj output = previous.GetFinalOutput();
Problems:
FinalOutputObj is coupled with all the processor implementations which is bad. It's not comprised of all the IChainedOutput child class members but uses a good subset to calculate other values.
FinalOutputObj is being composed in a bad way and I don't see how I can escape from outputting null values if the list of processors does not contain every processor implemented.
There is a lot of downcasting in the constructors of the child classes which is a red flag for oop. However, the inputs for each block of processing logic are completely different. First input is a couple of vectors, second input is the output of the first which includes a handful of custom types and more vectors, etc
Each IChainedOutput contains the reference to the inputs used to create it. currently there is one to one mapping input to processor but i'm not sure in future. And this is more bad downcasting.
I'd like to not have to perfectly organise the list of processors, makes it too easy for other developers to make mistakes here. so the next one selected should be the one that has the correct constructor.
You could try a decorator approach like this:
public interface IChainProcessor
{
IChainOutput Run(IChainOutput previousOutput);
}
public interface IChainOutput
{
string Value { get; }
}
public class OutputExample : IChainOutput
{
public string Value { get; }
public OutputExample(string value)
{
this.Value = value;
}
}
public abstract class Processor : IChainProcessor
{
protected IChainProcessor nextProcessor;
public IChainOutput Run(IChainOutput previousOutput)
{
var myOutput = this.MyLogic(previousOutput);
return this.nextProcessor == null ? myOutput : this.nextProcessor.Run(myOutput);
}
protected abstract IChainOutput MyLogic(IChainOutput input);
}
public class ProcessorA : Processor
{
public ProcessorA() { }
public ProcessorA(ProcessorB nextProcessor)
{
this.nextProcessor = nextProcessor;
}
protected override IChainOutput MyLogic(IChainOutput input)
{
return new OutputExample($"{input.Value} + Processor_A_Output");
}
}
public class ProcessorB : ProcessorA
{
public ProcessorB() { }
public ProcessorB(ProcessorC nextProcessor)
{
this.nextProcessor = nextProcessor;
}
protected override IChainOutput MyLogic(IChainOutput input)
{
return new OutputExample($"{input.Value} + Processor_B_Output");
}
}
public class ProcessorC : ProcessorB
{
protected override IChainOutput MyLogic(IChainOutput input)
{
return new OutputExample($"{input.Value} + Processor_C_Output");
}
}
The usage would be something like the below:
private static int Main(string[] args)
{
var chain = new ProcessorA(new ProcessorB(new ProcessorC()));
var simpleChain = new ProcessorA(new ProcessorC());
var verySimpleChain = new ProcessorA();
var initialInput = new OutputExample("Start");
Console.WriteLine(chain.Run(initialInput).Value);
Console.WriteLine(simpleChain.Run(initialInput).Value);
Console.WriteLine(verySimpleChain.Run(initialInput).Value);
return 0;
}
The output of this example is:
Start + Processor_A_Output + Processor_B_Output + Processor_C_Output
Start + Processor_A_Output + Processor_C_Output
Start + Processor_A_Output
The abstract Processor class provides a template method that you can implement in subclasses. So every ProcessorX class only defines MyLogic(IChainOutput input)
The Processors extend each other to enforce compile time preservation of processor order. So it is impossible to build a chain where ProcessorB comes before ProcessorA. It is possible though to build a chain that omits some processors as in the above example.
The example I provide here does not cater for the final output, which I know is one of your main concerns. To deal with issue I would rather build a mapping class to convert IChainOutput into the final format (I don't know the real structure of your data so maybe this is not possible).
in some of my cases it would make sense to have the output of one processor be the input for multiple other processors
Using this pattern it would also be possible to construct a processor 'tree' rather than a chain, by allowing the Processor class to have a list of next steps. Your usage would then become something like this:
var chain = new ProcessorA(new ProcessorB(new ProcessorC()), new ProcessorB(new ProcessorD()));
I hope this can help you.
If I understood your explanation correctly you can use delegates to overcome your problem. One of the important point about delegates is that they can be chained together so that you can call any number of methods in a single event.
Each processor transforming specific input into a specific output. Therefore the processor implementation should know only two types.
public interface IStepProcessor<TInput, TOutput>
{
TOutput Process(TInput input);
}
The client code ideally should know only two type of data that is input data and final product. The client code don't care if there were some intermediary steps in the middle. Client make use the conveyor as a black box
public delegate TOutput Conveyor<TInput, TOutput>(TInput input);
Yet some external code should understand how the whole transformation is done. This code should know all the intermediate data types and have access to all intermediate processors. It is done best with dependency injection.
public class Factory
{
private readonly IStepProcessor<IDataInput, IDataStep1> m_Step1;
private readonly IStepProcessor<IDataStep1, IDataStep2> m_Task2;
private readonly IStepProcessor<IDataStep2, IDataStep3> m_Task3;
private readonly IStepProcessor<IDataStep3, IDataStepN> m_TaskN;
private readonly IStepProcessor<IDataStepN, IDataOutput> m_FinalTask;
public Factory(
IStepProcessor<IDataInput, IDataStep1> task1,
IStepProcessor<IDataStep1, IDataStep2> task2,
IStepProcessor<IDataStep2, IDataStep3> task3,
IStepProcessor<IDataStep3, IDataStepN> taskN,
IStepProcessor<IDataStepN, IDataOutput> finalTask
)
{
m_Step1 = task1;
m_Task2 = task2;
m_Task3 = task3;
m_TaskN = taskN;
m_FinalTask = finalTask;
}
public Conveyor<IDataInput, IDataOutput> BuildConveyor()
{
return (input) =>
{
return m_FinalTask.Process(
m_TaskN.Process(
m_Task3.Process(
m_Task2.Process(
m_Step1.Process(input)))));
};
}
}
Here goes my offer
public interface IDataInput { }
public interface IDataStep1 { }
public interface IDataStep2 { }
public interface IDataStep3 { }
public interface IDataStepN { }
public interface IDataOutput { }
public interface IStepProcessor<TInput, TOutput>
{
TOutput Process(TInput input);
}
public delegate TOutput Conveyor<TInput, TOutput>(TInput input);
public class Factory
{
private readonly IStepProcessor<IDataInput, IDataStep1> m_Step1;
private readonly IStepProcessor<IDataStep1, IDataStep2> m_Task2;
private readonly IStepProcessor<IDataStep2, IDataStep3> m_Task3;
private readonly IStepProcessor<IDataStep3, IDataStepN> m_TaskN;
private readonly IStepProcessor<IDataStepN, IDataOutput> m_FinalTask;
public Factory(
IStepProcessor<IDataInput, IDataStep1> task1,
IStepProcessor<IDataStep1, IDataStep2> task2,
IStepProcessor<IDataStep2, IDataStep3> task3,
IStepProcessor<IDataStep3, IDataStepN> taskN,
IStepProcessor<IDataStepN, IDataOutput> finalTask
)
{
m_Step1 = task1;
m_Task2 = task2;
m_Task3 = task3;
m_TaskN = taskN;
m_FinalTask = finalTask;
}
public Conveyor<IDataInput, IDataOutput> BuildConveyor()
{
return (input) =>
{
return m_FinalTask.Process(
m_TaskN.Process(
m_Task3.Process(
m_Task2.Process(
m_Step1.Process(input)))));
};
}
}
public class Client
{
private readonly Conveyor<IDataInput, IDataOutput> m_Conveyor;
public Client(Conveyor<IDataInput, IDataOutput> conveyor)
{
m_Conveyor = conveyor;
}
public void DealWithInputAfterTransformingIt(IDataInput input)
{
var output = m_Conveyor(input);
Console.Write($"Mind your business here {typeof(IDataOutput).IsAssignableFrom(output.GetType())}");
}
}
public class Program {
public void StartingPoint(IServiceProvider serviceProvider)
{
ISomeDIContainer container = CreateDI();
container.Register<IStepProcessor<IDataInput, IDataStep1>, Step1Imp>();
container.Register<IStepProcessor<IDataStep1, IDataStep2>, Step2Imp>();
container.Register<IStepProcessor<IDataStep2, IDataStep3>, Step3Imp>();
container.Register<IStepProcessor<IDataStep3, IDataStepN>, StepNImp>();
container.Register<IStepProcessor<IDataStepN, IDataOutput>, StepOImp>();
container.Register<Factory>();
Factory factory = container.Resolve<Factory>();
var conveyor = factory.BuildConveyor();
var client = new Client(conveyor);
}
}
I have an object that can be of type AudioRequest or VideoRequest. Both classes inherit from Request. I have this class:
public static DoThings
{
public static void HandleRequest(AudioRequest r)
{
// Do things.
}
public static void HandleRequest(VideoRequest r)
{
// Do things.
}
}
I want to be able to call DoThings.HandleRequest(r) where r can be either a VideoRequest or AudioRequest and have it call the correct one. Is that possible? I have no control over the *Request classes, so I can't do anything to them. I do have control of the DoThings class and the code that calls HandleRequest. This is the code that calls it, it is WebAPI:
public Response Post(Request input)
{
return DoThings.HandleRequest(input);
}
The code above gives the error Argument 1: cannot convert from 'Request' to 'AudioRequest'.
The original code that I was cleaning up had this:
if (input.GetType() == typeof(AudioRequest))
{
var audioRequest = (AudioRequest)input;
DoThings.HandleRequest(audioRequest);
}
else if (input.GetType() == typeof(VideoRequest))
{
var videoRequest = (VideoRequest)input;
DoThings.HandleRequest(videoRequest);
}
But I figured there was a cleaner way to do this.
Based on the information you've provided so far, your question appears to be a duplicate of How to call a function dynamically based on an object type. I agree with the answer, that the fact that you want to do this suggests you should rethink the design. But, you can use dynamic to accomplish what you want.
Here's a simple console program that demonstrates the basic idea:
class Program
{
static void Main(string[] args)
{
A b = new B(), c = new C();
M(b);
M(c);
}
static void M(A a)
{
WriteLine("M(A)");
M((dynamic)a);
}
static void M(B b)
{
WriteLine("M(B)");
}
static void M(C c)
{
WriteLine("M(C)");
}
}
class A { }
class B : A { }
class C : A { }
The output is:
M(A)
M(B)
M(A)
M(C)
As you can see, in each case the M(A) method is called first, and then the appropriate M(B) or M(C) overload is called from M(A).
In your own example, this could look something like this:
public static DoThings
{
public static void HandleRequest(Request r)
{
// Dynamic dispatch to actual method:
HandleRequest((dynamic)r);
}
public static void HandleRequest(AudioRequest r)
{
// Do things.
}
public static void HandleRequest(VideoRequest r)
{
// Do things.
}
}
Note that dynamic does incur a run-time cost, particularly the first time a method is called with a given run-time type. But depending on the frequency and complexity of these "requests", using dynamic could be the cleanest way out of the current situation.
C# will call the appropriate function that matches the arguments and their types.
That being said, both of your functions accept AudioRequest, I believe one of those should accept a VideoRequest.
public static DoThings
{
public static void HandleRequest(AudioRequest r)
{
// Do things.
}
public static void HandleRequest(VideoRequest r)
{
// Do things.
}
}
If for some reason you must have two different functions that take only AudioRequest you can differentiate between two function with an extra parameter
public static class DoThings
{
public static void HandleRequest(AudioRequest r)
{
// Do things.
}
public static void HandleRequest(AudioRequest r, bool UseAlternativeMethod)
{
// Do other things.
}
}
Simply having a second parameter will call the second method regardless of it's value.
This isn't a best practices solution as you'd rather discriminate between them by accurately renaming the method name to be accurate but in practice you don't always have a choice.
I'd like to be able to specify an Action<string> at the app level that my library could then use for progress reporting. ConfigurationManager.AppSettings only allows XmlSerializeables, and Actions are not that.
The motivation is that console apps might just write to the console, webapps perhaps to a trace, and forms perhaps to files or a particular field, the point is the app should be able to configure it imo.
My approach currently is to have in the library a LibSettings class that has a static settable Action<string>. That means anyone can set it elsewhere too, which poses potential for bugs.
At first I thought maybe a static constructor (with parameters) would do but it turns out you can't call static constructors explicitly and you certainly can't give them parameters.
Is there any way to achieve my goal of being able to specify the Feedback action once and only onc in some sort of custom app settings, and not throw a runtime exception on second setting, or swallow the second setting? That is essentially like a singleton property of my design when I design it. Thanks in advance.
Serializing and deserializing a delegate usually isn't a good idea, as it easily leads to pretty serious security concerns (see arbitrary code execution).
Instead I would recommend having a enum or similar serializable type that identifies a number of statically defined functions and convert between them. Something like this:
public enum FeedbackAction
{
Console,
Trace,
...
}
public static class FeedbackActions
{
public static void Console(string text) { ... }
public static void Trace(string text) { ... }
public static Action<string> GetAction(FeedbackAction action)
{
switch (action)
{
case FeedbackAction.Console:
return Console;
case FeedbackAction.Trace:
return Trace;
default:
throw new ArgumentException("Invalid feedback action.", nameof(action));
}
}
}
Now whenever you're trying to use the app setting, just call FeedbackActions.GetAction to convert between your enum values and the appropriate Action<string>.
For example:
public static class Feedback
{
public static Action<string> feedbackAction;
public static object syncLock = new object();
public static void ProvideFeedback(string text)
{
if (feedbackAction == null)
{
// synchronize to avoid duplicate calls
lock (syncLock)
{
if (feedbackAction == null)
{
var value = ConfigurationManager.AppSettings["FeedbackAction"];
feedbackAction = FeedbackActions.GetAction(value);
}
}
}
feedbackAction(text);
}
}
This way you can safely call Feedback.ProvideFeedback, and its behavior will be driven by the app/web.config file.
If you need to make a solution that's flexible enough to handle almost any feedback action, I'd strongly recommend reading up on inversion of control in general and the Managed Extensibility Framework (MEF) in particular. A full implementation would be a bit too complex to provide here, but in general it would look a bit like this:
public interface IFeedbackAction
{
void ProvideFeedback(string text);
}
public interface IFeedbackMetadata
{
string Name { get; }
}
[Export(typeof(IFeedbackAction)), ExportMetadata("Name", "Console")]
public interface ConsoleFeedbackAction : IFeedbackAction { ... }
[Export(typeof(IFeedbackAction)), ExportMetadata("Name", "Trace")]
public interface TraceFeedbackAction : IFeedbackAction { ... }
public static class Feedback
{
[ImportMany]
public IEnumerable<Lazy<IFeedbackAction, IFeedbackMetadata>> FeedbackActions { get; set; }
private IFeedbackAction feedbackAction;
public static void ProvideFeedback(string text)
{
if (feedbackAction == null)
{
// synchronize to avoid duplicate calls
lock (syncLock)
{
if (feedbackAction == null)
{
var value = ConfigurationManager.AppSettings["FeedbackAction"];
feedbackAction = GetFeedbackAction(value);
}
}
}
feedbackAction.ProvideFeedback(text);
}
private static IFeedbackAction GetFeedbackAction(string name)
{
return FeedbackActions
.First(l => l.Metadata.Name.Equals(name)).Value;
}
}
With this method, consumers would be able to provide their own implementation of IFeedbackAction, decorated with the appropriate [Export] and [ExportMetadata] attributes, and simply specify use of their custom actions in the app/web.config file.
Ok, let's see if I inderstood all right.
Let's suppose this is your config class:
public static class LibSettings
{
public static readonly Action<string> TheAction{ get; private set; }
static LibSettings()
{
var action = ConfigurationManager.AppSettings["libAction"];
switch(action)
{
case "console":
TheAction = ConsoleAction;
break;
case "web":
TheAction = WebAction;
break;
//And as many as you need...
}
}
private static void ConsoleAction(string Parameter)
{
//Whatever it does...
}
private static void WebAction(string Parameter)
{
//Whatever it does...
}
}
Is this what you meant? it will be only set once whenever you access any property of the class, it cannot be modified externally and will change the Action upon an AppSeting record.
Ok, let's go with another approach. Now we will have two classes a temporal holder where you will set the action you want and the current settings class.
public static class TemporalHolder
{
public static Action<string> HeldAction{ get; set; }
}
public static class LibSettings
{
public static readonly Action<string> TheAction;
static LibSettings()
{
TheAction = TemporalHolder.HeldAction;
}
public static void Init()
{
/*Just do nothing as we will use it to fire the constructor*/
}
}
And now, to use it, just seth the action to the temporal holder and call anithing static on LibSettings:
TemporalHolder.Action = (your function);
LibSettings.Init();
And voila! no errors on second settings, it cannot be changed on runtime and cannot be reasigned. are all the conditions met?
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?
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*/};
}
}
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.
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) { }
Let's say we have the following piece of code:
public class Event { }
public class SportEvent1 : Event { }
public class SportEvent2 : Event { }
public class MedicalEvent1 : Event { }
public class MedicalEvent2 : Event { }
public interface IEventFactory
{
bool AcceptsInputString(string inputString);
Event CreateEvent(string inputString);
}
public class EventFactory
{
private List<IEventFactory> factories = new List<IEventFactory>();
public void AddFactory(IEventFactory factory)
{
factories.Add(factory);
}
//I don't see a point in defining a RemoveFactory() so I won't.
public Event CreateEvent(string inputString)
{
try
{
//iterate through all factories. If one and only one of them accepts
//the string, generate the event. Otherwise, throw an exception.
return factories.Single(factory => factory.AcceptsInputString(inputString)).CreateEvent(inputString);
}
catch (InvalidOperationException e)
{
throw new InvalidOperationException("Either there was no valid factory avaliable or there was more than one for the specified kind of Event.", e);
}
}
}
public class SportEvent1Factory : IEventFactory
{
public bool AcceptsInputString(string inputString)
{
return inputString.StartsWith("SportEvent1");
}
public Event CreateEvent(string inputString)
{
return new SportEvent1();
}
}
public class MedicalEvent1Factory : IEventFactory
{
public bool AcceptsInputString(string inputString)
{
return inputString.StartsWith("MedicalEvent1");
}
public Event CreateEvent(string inputString)
{
return new MedicalEvent1();
}
}
And here is the code that runs it:
static void Main(string[] args)
{
EventFactory medicalEventFactory = new EventFactory();
medicalEventFactory.AddFactory(new MedicalEvent1Factory());
medicalEventFactory.AddFactory(new MedicalEvent2Factory());
EventFactory sportsEventFactory = new EventFactory();
sportsEventFactory.AddFactory(new SportEvent1Factory());
sportsEventFactory.AddFactory(new SportEvent2Factory());
}
I have a couple of questions:
Instead of having to add factories
here in the main method of my
application, should I try to
redesign my EventFactory class so it
is an abstract factory? It'd be
better if I had a way of not having
to manually add
EventFactories every time I want to
use them. So I could just instantiate MedicalFactory and SportsFactory. Should I make a Factory of factories? Maybe that'd be over-engineering?
As you have probably noticed, I am using a inputString string as argument to feed the factories. I have an application that lets the user create his own events but also to load/save them from text files. Later, I might want to add other kinds of files, XML, sql connections, whatever. The only way I can think of that would allow me to make this work is having an internal format (I choose a string, as it's easy to understand). How would you make this? I assume this is a recurrent situation, probably most of you know of any other more intelligent approach to this. I am then only looping in the EventFactory for all the factories in its list to check if any of them accepts the input string. If one does, then it asks it to generate the Event.
If you find there is something wrong or awkward with the method I'm using to make this happen, I'd be happy to hear about different implementations. Thanks!
PS: Although I don't show it in here, all the different kind of events have different properties, so I have to generate them with different arguments (SportEvent1 might have SportName and Duration properties, that have to be put in the inputString as argument).
I am not sure about the input string question but for the first question you can likely use "convention over configuration"; a combination of reflection, the IEventFActory type and the naming you already have in place, Name.EndsWith("EventFactory") should allow you to instantiate the factories and get them into their Lists with code.
HTH ,
Berryl