I have a library of classes that describe different pieces of connecting hardware such as nails, screws and bolts that we will call the ConnectorLibrary. I am attempting to build a library on top of that one that will handle analyzing the grip capacity of each class in that library that we will call ConnectorGripAnalysisLibrary.
For this question we will work with the classes: Screw, Bolt, and Connector. Both Screw and Bolt inherit from Connector (which is an abstract class) and they are both implemented in the ConnectorLibrary.
There is a different method for determining grip for each class in the base library that I need to implement. So for both Bolt and Screw I need to Implement a method such as DoesPassGripTest(Board board). (Board being just an example parameter)
If I were going to implement this in the Connectorlibrary, I would put DoesPassGripTest into Connector an abstract method and implement the different formulas in the respective derived classes.
The goal is to be able to have my code work like this from the ConnectorGripAnalysisLibrary:
[Test()]
public static void CheckScrewAndBoltGripTest()
{
Board board = new Board();
Bolt b = new Bolt();
Screw s = new Screw();
List<Connector> connectors = new List<Connector>()
connectors.add(b);
connectors.add(s);
foreach(var connector in connectors)
{
if(!connector.DoesPassGripTest(board));
throw new Exception("Grip Test Fails");
}
}
I want to maintain the "Open closed principle" in the ConnectorGripAnalysisLibrary, so that in the event a new Connector is added to the ConnectorLibary, no modification of the ConnectorGripAnalysisLibrary is needed other than adding a new class. "Open for Extension, Closed for Modificaiton"
But how can I build this functionality into the GripAnalysisLibrary that is built on top of the ConnectorLibrary. Is there a slick way that I can do this?
I don't want the ConnectorLibrary to contain the GripAnalysis code and functionality. The ConnectorLibrary is to be opensource while the GripAnalysisLibrary will be proprietary.
For doing this as an extension method you need to create a class to define extensions for Connector and include the class wherever you want to use the DoesPassGripTest method on a Connector instance. The basic outline of the extension is:
public static class ConnectorExtensions
{
public static bool DoesPassGripTest(this Connector connector, Board board)
{
// Some logic to determine which connector is being used
}
}
I don't know if there is any other method for determining which connector is being passed in other than type checking since you didn't provide any details about Connectors or the grip analysis logic. Your extension would need to know how to evaluate the test for a given board for each Connector type you are given.
EDIT:
Based on your desire to have your ConnectorGripAnalysisLibrary be easily extendable and without modification, here is pseudo-code of an approach using reflection that allows you to only need to add a class for each new connector.
Create an interface that supplies information to run the analysis and which type of Connector it is for:
public interface IConnectorGripAnalyzer
{
Type ConnectorType { get; }
bool DoesPassGripTest(Board board);
}
Create a base class using generics for easy implementations of concrete classes:
public class ConnectorGripAnalyzer<T> : IConnectorGripAnalyzer where T : Connector
{
public Type ConnectorType
{
get { return typeof(T); }
}
public virtual bool DoesPassGripTest(Board board)
{
return true;
}
}
Create a repository that can be used to get an IConnectorGripAnalyzer instance by Type using reflection. On first use it gathers all of the various analyzers and stores them by connector Type:
public static class ConnectorAnalyzerRepository
{
private Dictionary<Type, IConnectorGripAnalyzer> connectorGripAnalyzers;
public IConnectorGripAnalyzer GetGripAnalyzer(Connector connector)
{
if (connectorGripAnalyzers == null)
{
connectorGripAnalyzers = new Dictionary<Type, IConnectorGripAnalyzer>();
var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(IConnectorGripAnalyzer).IsAssignableFrom(t));
foreach (var t in types)
{
var c = Activator.CreateInstance(t) as IConnectorGripAnalyzer;
if (c == null)
continue;
connectorGripAnalyzers[c.ConnectorType] = c;
}
}
return connectorGripAnalyzers.ContainsKey(typeof(connector)) ? connectorGripAnalyzers[typeof(connector)] : null;
}
}
The extension for Connector leverages the repository to create an appropriate IConnectorGripAnalyzer instance for the given Connector. In the case that the Type of the Connector has no implementation the example throws an exception, but you could return false or log it as a configuration issue as well:
public static class ConnectorExtensions
{
public static bool DoesPassGripTest(this Connector connector, Board board)
{
var analyzer = ConnectorAnalyzerRepository.GetGripAnalyzer(connector);
if (analyzer == null)
throw new ArgumentException("Invalid connector type"); // Do whatever you want with the failure
return analyzer.DoesPassGripTest(board);
}
}
Adding support for a Connector in the ConnectorGripAnalysisLibrary is now a matter of adding a class that inherits from ConnectorGripAnalyzer with the concrete Connector type. All that is needed is an appropriate override of DoesPassGripTest(Board board) for the specific Connector:
public class NailConnectorGripAnalyzer : ConnectorGripAnalyzer<NailConnector>
{
public override bool DoesPassGripTest(Board board)
{
return true;
}
}
public class ScrewConnectorGripAnalyzer : ConnectorGripAnalyzer<ScrewConnector>
{
public override bool DoesPassGripTest(Board board)
{
return true;
}
}
Related
For my project purpose I need to send metrics to AWS.
I have main class called SendingMetrics.
private CPUMetric _cpuMetric;
private RAMMetric _ramMetric;
private HDDMetric _hddMetric;
private CloudWatchClient _cloudWatchClient(); //AWS Client which contains method Send() that sends metrics to AWS
public SendingMetrics()
{
_cpuMetric = new CPUMetric();
_ramMetric = new RAMMetric();
_hddMetric = new HDDMetric();
_cloudwatchClient = new CloudwatchClient();
InitializeTimer();
}
private void InitializeTimer()
{
//here I initialize Timer object which will call method SendMetrics() each 60 seconds.
}
private void SendMetrics()
{
SendCPUMetric();
SendRAMMetric();
SendHDDMetric();
}
private void SendCPUMetric()
{
_cloudwatchClient.Send("CPU_Metric", _cpuMetric.GetValue());
}
private void SendRAMMetric()
{
_cloudwatchClient.Send("RAM_Metric", _ramMetric.GetValue());
}
private void SendHDDMetric()
{
_cloudwatchClient.Send("HDD_Metric", _hddMetric.GetValue());
}
Also I have CPUMetric, RAMMetric and HDDMetric classes that looks pretty much similar so I will just show code of one class.
internal sealed class CPUMetric
{
private int _cpuThreshold;
public CPUMetric()
{
_cpuThreshold = 95;
}
public int GetValue()
{
var currentCpuLoad = ... //logic for getting machine CPU load
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
So the problem I have is that clean coding is not satisfied in my example. I have 3 metrics to send and if I need to introduce new metric I will need to create new class, initialize it in SendingMetrics class and modify that class and that is not what I want. I want to satisfy Open Closed principle, so it is open for extensions but closed for modifications.
What is the right way to do it? I would move those send methods (SendCPUMetric, SendRAMMetric, SendHDDMetric) to corresponding classes (SendCPUMetric method to CPUMetric class, SendRAMMEtric to RAMMetric, etc) but how to modfy SendingMetrics class so it is closed for modifications and if I need to add new metric to not change that class.
In object oriented languages like C# the Open Closed Principle (OCP) is usually achieved by using the concept of polymorphism. That is that objects of the same kind react different to one and the same message. Looking at your class "SendingMetrics" it's obvious that the class works with different types of "Metrics". The good thing is that your class "SendingMetrics" talks to a all types of metrics in the same way by sending the message "getData". Hence you can introduce a new abstraction by creating an Interface "IMetric" that is implemented by the concrete types of metrics. That way you decouple your "SendingMetrics" class from the concrete metric types wich means the class does not know about the specific metric types. It only knows IMetric and treats them all in the same way wich makes it possible to add any new collaborator (type of metric) that implements the IMetric interface (open for extension) without the need to change the "SendingMetrics" class (closed for modification). This also requires that the objects of the different types of metrics are not created within the "SendingMetrics" class but e.g. by a factory or outside of the class and being injected as IMetrics.
In addition to using inheritance to enable polymorphism and achiving OCP by introducing the interface IMetric you can also use inheritance to remove redundancy. Which means you can introduce an abstract base class for all metric types that implements common behaviour that is used by all types of metrics.
Your design is almost correct. You got 3 data retriever and 1 data sender. So it's easy to add more metric (more retriever) (open for extensions) without affecting current metrics (closed for modifications), you just need a bit more refactor to reduce duplicated code.
Instead of have 3 metrics classes look very similar. Only below line is different
var currentCpuLoad = ... //logic for getting machine CPU load
You can create a generic metric like this
internal interface IGetMetric
{
int GetData();
}
internal sealed class Metric
{
private int _threshold;
private IGetMetric _getDataService;
public Metric(IGetMetric getDataService)
{
_cpuThreshold = 95;
_getDataService = getDataService;
}
public int GetValue()
{
var currentCpuLoad = _getDataService.GetData();
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
Then just create 3 GetMetric classes to implement that interface. This is just 1 way to reduce the code duplication. You can also use inheritance (but I don't like inheritance). Or you can use a Func param.
UPDATED: added class to get CPU metric
internal class CPUMetricService : IGetMetric
{
public int GetData() { return ....; }
}
internal class RAMMetricService : IGetMetric
{
public int GetData() { return ....; }
}
public class AllMetrics
{
private List<Metric> _metrics = new List<Metric>()
{
new Metric(new CPUMetricService());
new Metric(new RAMMetricService());
}
public void SendMetrics()
{
_metrics.ForEach(m => ....);
}
}
I am learning Adapter pattern, and used following link to see code. Difference in my code and example code is, I removed ITarget interface, and directly created object in Client.
I know importance of using Interface, but is it really necessary to use interface, more specifically, by not creating interface, am I violating Adapter Pattern rule?
Adapter Pattern Example
My Code (without interface)
class Program
{
static void Main(string[] args)
{
Adapter obj = new Adapter();
Client client = new Client(obj);
client.MakeRequest();
}
}
public class Client
{
private Adapter _target;
public Client(Adapter target)
{
_target = target;
}
public void MakeRequest()
{
_target.MethodA();
}
}
public class Adaptee
{
public void MethodB()
{
Console.WriteLine("MethodB called");
}
}
public class Adapter
{
Adaptee _adaptee = new Adaptee();
public void MethodA()
{
_adaptee.MethodB();
}
}
Thanks.
The whole point of an adapter is that the adaptee can be used wherever a certain type is needed which is not the adaptee's type.
Assume that you have a method MyMethod(MyParameterType m). This method expects a parameter of type MyParameterType. But you don't have an object of this type. Instead you have an object that has similar functionality (maybe from a third-party library). However, this object is not of type MyParameterType, but of type MyOtherType. Of course, you can't directly pass the object to the method. That's where the adapter comes into play.
You need an object to pass to the method. Hence, it is essential that this object is of type MyParameterType; may it be an interface or class. So the Adapter has to implement or inherit this type. Otherwise, it does not make sense. You would just have another class with the same functionality as the object of type MyOtherType, but you can't use it anywhere.
Summarizing, the adapter is used to bridge architectural mismatch. This often occurs when you have several libraries that need to play together but were not supposed to do so. If you have only code that has been developed by yourself, adapters are rarely necessary because you can let the objects just implement the interface you need. This is not possible in third-party code. So you introduce adapters for that. So in the end, the adapter disguises an object to look familiar to a client, even if it is not. The interface is necessary to make it familiar. So yes, your code is not an adapter.
The problem here is you've explicitly coupled Client to the Adapter and implicitly to the behavior of how that adapter works.
Interfaces and this pattern pay off when you start using dependency injection.
Assume I have:
public Client(IAdapter target) ...
Now I can change the behavior of the adapter implementation without the Client class being changed at all:
interface IAdapter
{
void MethodA();
}
interface IAdaptee
{
void MethodB();
}
class Adapter<TAdaptee> : IAdapter where TAdaptee : IAdaptee, new()
{
private TAdaptee _adaptee;
public Adapter()
{
_adaptee = new TAdaptee();
}
public void MethodA()
{
_adaptee.MethodB();
}
}
class AdapteeA : IAdaptee
{
public void MethodB()
{
Console.WriteLine("AdapteeA");
}
}
class AdapteeB : IAdaptee
{
public void MethodB()
{
Console.WriteLine("AdapteeB");
}
}
Then with something like NInject you bind up your system:
class Program
{
private static StandardKernel _kernel;
static void Main(string[] args)
{
_kernel = new StandardKernel();
_kernel.Bind<IAdapter>().To<Adapter<AdapteeA>>();
var adapter = _kernel.Get<IAdapter>();
adapter.MethodA();
}
}
You can change your adapter and your adaptee, without client ever knowing the difference. i.e. Client is decoupled from both.
Again to make this point I can change to AdapteeB:
_kernel.Bind<IAdapter>().To<Adapter<AdapteeB>>();
It does go further too, with things like contra-variance, but that is beyond scope.
C#. I have a base class called FileProcessor:
class FileProcessor {
public Path {get {return m_sPath;}}
public FileProcessor(string path)
{
m_sPath = path;
}
public virtual Process() {}
protected string m_sath;
}
Now I'd like to create to other classes ExcelProcessor & PDFProcessor:
class Excelprocessor: FileProcessor
{
public void ProcessFile()
{
//do different stuff from PDFProcessor
}
}
Same for PDFProcessor, a file is Excel if Path ends with ".xlsx" and pdf if it ends with ".pdf". I could have a ProcessingManager class:
class ProcessingManager
{
public void AddProcessJob(string path)
{
m_list.Add(Path;)
}
public ProcessingManager()
{
m_list = new BlockingQueue();
m_thread = new Thread(ThreadFunc);
m_thread.Start(this);
}
public static void ThreadFunc(var param) //this is a thread func
{
ProcessingManager _this = (ProcessingManager )var;
while(some_condition) {
string fPath= _this.m_list.Dequeue();
if(fPath.EndsWith(".pdf")) {
new PDFProcessor().Process();
}
if(fPath.EndsWith(".xlsx")) {
new ExcelProcessor().Process();
}
}
}
protected BlockingQueue m_list;
protected Thread m_thread;
}
I am trying to make this as modular as possible, let's suppose for example that I would like to add a ".doc" processing, I'd have to do a check inside the manager and implement another DOCProcessor.
How could I do this without the modification of ProcessingManager? and I really don't know if my manager is ok enough, please tell me all your suggestions on this.
I'm not really aware of your problem but I'll try to give it a shot.
You could be using the Factory pattern.
class FileProcessorFactory {
public FileProcessor getFileProcessor(string extension){
switch (extension){
case ".pdf":
return new PdfFileProcessor();
case ".xls":
return new ExcelFileProcessor();
}
}
}
class IFileProcessor{
public Object processFile(Stream inputFile);
}
class PdfFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
class ExcelFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
This should make sure you are using the FileProcessorFactory to get the correct processor, and the IFileProcessor will make sure you're not implementing different things for each processor.
and implement another DOCProcessor
Just add a new case to the FileProcessorFactory, and a new class which implements the interface IFileProcessor called DocFileProcessor.
You could decorate your processors with custom attributes like this:
[FileProcessorExtension(".doc")]
public class DocProcessor()
{
}
Then your processing manager could find the processor whose FileProcessorExtension property matches your extension, and instantiate it reflexively.
I agree with Highmastdon, his factory is a good solution. The core idea is not to have any FileProcessor implementation reference in your ProcessingManager anymore, only a reference to IFileProcessor interface, thus ProcessingManager does not know which type of file it deals with, it just knows it is an IFileProcessor which implements processFile(Stream inputFile).
In the long run, you'll just have to write new FileProcessor implementations, and voila. ProcessingManager does not change over time.
Use one more method called CanHandle for example:
abstract class FileProcessor
{
public FileProcessor()
{
}
public abstract Process(string path);
public abstract bool CanHandle(string path);
}
With excel file, you can implement CanHandle as below:
class Excelprocessor: FileProcessor
{
public override void Process(string path)
{
}
public override bool CanHandle(string path)
{
return path.EndsWith(".xlsx");
}
}
In ProcessingManager, you need a list of processor which you can add in runtime by method RegisterProcessor:
class ProcessingManager
{
private List<FileProcessor> _processors;
public void RegisterProcessor(FileProcessor processor)
{
_processors.Add(processor)
}
....
So LINQ can be used in here to find appropriate processor:
while(some_condition)
{
string fPath= _this.m_list.Dequeue();
var proccessor = _processors.SingleOrDefault(p => p.CanHandle(fPath));
if (proccessor != null)
proccessor.Process(proccessor);
}
If you want to add more processor, just define and add it into ProcessingManager by using
RegisterProcessor method. You also don't change any code from other classes even FileProcessorFactory like #Highmastdon's answer.
You could use the Factory pattern (a good choice)
In Factory pattern there is the possibility not to change the existing code (Follow SOLID Principle).
In future if a new Doc file support is to be added, you could use the concept of Dictionaries. (instead of modifying the switch statement)
//Some Abstract Code to get you started (Its 2 am... not a good time to give a working code)
1. Define a new dictionary with {FileType, IFileProcessor)
2. Add to the dictionary the available classes.
3. Tomorrow if you come across a new requirement simply do this.
Dictionary.Add(FileType.Docx, new DocFileProcessor());
4. Tryparse an enum for a userinput value.
5. Get the enum instance and then get that object that does your work!
Otherwise an option: It is better to go with MEF (Managed Extensibility Framework!)
That way, you dynamically discover the classes.
For example if the support for .doc needs to be implemented you could use something like below:
Export[typeof(IFileProcessor)]
class DocFileProcessor : IFileProcessor
{
DocFileProcessor(FileType type);
/// Implement the functionality if Document type is .docx in processFile() here
}
Advantages of this method:
Your DocFileProcessor class is identified automatically since it implements IFileProcessor
Application is always Extensible. (You do an importOnce of all parts, get the matching parts and Execute.. Its that simple!)
I chose to expose some new behavior using composition vs. injecting a new object into my consumers code OR making the consumer provide their own implementation of this new behavior. Did I make a bad design decision?
I had new requirements that said that I needed to implement some special behavior in only certain circumstances. I chose to define a new interface, implement the new interface in a concrete class that was solely responsible for carrying out the behavior. Finally, in the concrete class that the consumer has a reference to, I implemented the new interface and delegate down to the class that does the work.
Here are the assumptions that I was working with...
I haven an interface, named IFileManager that allows implementors to manage various types of files
I have a factory that returns a concrete implementation of IFileManager
I have 3 implementations of IFileManager, these are (LocalFileManager, DfsFileManager, CloudFileManager)
I have a new requirements that says that I need to manage permissions for only the files being managed by the CloudFileManager, so the behavior for managing permissions is unique to the CloudFileManager
Here is the test that led me to the code that I wrote...
[TestFixture]
public class UserFilesRepositoryTest
{
public interface ITestDouble : IFileManager, IAclManager { }
[Test]
public void CreateResume_AddsPermission()
{
factory.Stub(it => it.GetManager("cloudManager")).Return(testDouble);
repository.CreateResume();
testDouble.AssertWasCalled(it => it.AddPermission());
}
[SetUp]
public void Setup()
{
testDouble = MockRepository.GenerateStub<ITestDouble>();
factory = MockRepository.GenerateStub<IFileManagerFactory>();
repository = new UserFileRepository(factory);
}
private IFileManagerFactory factory;
private UserFileRepository repository;
private ITestDouble testDouble;
}
Here is the shell of my design (this is just the basic outline not the whole shibang)...
public class UserFileRepository
{
// this is the consumer of my code...
public void CreateResume()
{
var fileManager = factory.GetManager("cloudManager");
fileManager.AddFile();
// some would argue that I should inject a concrete implementation
// of IAclManager into the repository, I am not sure that I agree...
var permissionManager = fileManager as IAclManager;
if (permissionManager != null)
permissionManager.AddPermission();
else
throw new InvalidOperationException();
}
public UserFileRepository(IFileManagerFactory factory)
{
this.factory = factory;
}
private IFileManagerFactory factory;
}
public interface IFileManagerFactory
{
IFileManager GetManager(string managerName);
}
public class FileManagerFactory : IFileManagerFactory
{
public IFileManager GetManager(string managerName)
{
IFileManager fileManager = null;
switch (managerName) {
case "cloudManager":
fileManager = new CloudFileManager();
break;
// other managers would be created here...
}
return fileManager;
}
}
public interface IFileManager
{
void AddFile();
void DeleteFile();
}
public interface IAclManager
{
void AddPermission();
void RemovePermission();
}
/// <summary>
/// this class has "special" behavior
/// </summary>
public class CloudFileManager : IFileManager, IAclManager
{
public void AddFile() {
// implementation elided...
}
public void DeleteFile(){
// implementation elided...
}
public void AddPermission(){
// delegates to the real implementation
aclManager.AddPermission();
}
public void RemovePermission() {
// delegates to the real implementation
aclManager.RemovePermission();
}
public CloudFileManager(){
aclManager = new CloudAclManager();
}
private IAclManager aclManager;
}
public class LocalFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
public class DfsFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
/// <summary>
/// this class exists to manage permissions
/// for files in the cloud...
/// </summary>
public class CloudAclManager : IAclManager
{
public void AddPermission() {
// real implementation elided...
}
public void RemovePermission() {
// real implementation elided...
}
}
Your approach to add your new behavior only saved you an initialization in the grand scheme of things because you to implemented CloudAclManager as separate from CloudFileManager anyways. I disagree with some things with how this integrates with your existing design (which isn't bad)...
What's Wrong With This?
You separated your file managers and made use of IFileManager, but you didn't do the same with IAclManager. While you have a factory to create various file managers, you automatically made CloudAclManager the IAclManager of CloudFileManager. So then, what's the point of having IAclManager?
To make matters worse, you
initialize a new CloudAclManager
inside of CloudFileManager every time you try to get its ACL
manager - you just gave factory
responsibilities to your
CloudFileManager.
You have CloudFileManager implement IAclManager on top of having it as a property. You just moved the rule that permissions are unique to CloudFileManager into your model layer rather than your business rule layer. This also results in supporting the unnecessary
potential of circular referencing between self and property.
Even if you wanted
CloudFileManager to delegate the
permission functionality to
CloudAclManager, why mislead other
classes into thinking that
CloudFileManager handles its own
permission sets? You just made your
model class look like a facade.
Ok, So What Should I Do Instead?
First, you named your class CloudFileManager, and rightly so because its only responsibility is to manage files for a cloud. Now that permission sets must also be managed for a cloud, is it really right for a CloudFileManager to take on these new responsibilities? The answer is no.
This is not to say that you can't have code to manage files and code to manage permissions in the same class. However, it would then make more sense for the class to be named something more general like CloudFileSystemManager as its responsibilities would not be limited to just files or permissions.
Unfortunately, if you rename your class it would have a negative effect on those currently using your class. So how about still using composition, but not changing CloudFileManager?
My suggestion would be to do the following:
1. Keep your IAclManager and create IFileSystemManager
public interface IFileSystemManager {
public IAclManager AclManager { get; }
public IFileManager FileManager { get; }
}
or
public interface IFileSystemManager : IAclManager, IFileManager {
}
2. Create CloudFileSystemManager
public class CloudFileSystemManager : IFileSystemManager {
// implement IFileSystemManager
//
// How each manager is set is up to you (i.e IoC, DI, simple setters,
// constructor parameter, etc.).
//
// Either way you can just delegate to the actual IAclManager/IFileManager
// implementations.
}
Why?
This will allow you to use your new behavior with minimal impact to your current code base / functionality without affecting those who are using your original code. File management and permission management can also coincide (i.e. check permissions before attempting an actual file action). It's also extensible if you need any other permission set manager or any other type of managers for that matter.
EDIT - Including asker's clarification questions
If I create IFileSystemManager : IFileManager, IAclManager, would the repository still use the FileManagerFactory and return an instance of CloudFileSystemManager?
No, a FileManagerFactory should not return a FileSystemManager. Your shell would have to update to use the new interfaces/classes. Perhaps something like the following:
private IAclManagerFactory m_aclMgrFactory;
private IFileManagerFactory m_fileMgrFactory;
public UserFileRepository(IAclManagerFactory aclMgrFactory, IFileManagerFactory fileMgrFactory) {
this.m_aclMgrFactory = aclMgrFactory;
this.m_fileMgrFactory = fileMgrFactory;
}
public void CreateResume() {
// I understand that the determination of "cloudManager"
// is non-trivial, but that part doesn't change. For
// your example, say environment = "cloudManager"
var environment = GetEnvMgr( ... );
var fileManager = m_fileMgrFactory.GetManager(environment);
fileManager.AddFile();
// do permission stuff - see below
}
As for invoking permission stuff to be done, you have a couple options:
// can use another way of determining that a "cloud" environment
// requires permission stuff to be done
if(environment == "cloudManager") {
var permissionManager = m_aclMgrFactory.GetManager(environment);
permissionManager.AddPermission();
}
or
// assumes that if no factory exists for the environment that
// no permission stuff needs to be done
var permissionManager = m_aclMgrFactory.GetManager(environment);
if (permissionManager != null) {
permissionManager.AddPermission();
}
I think that composition is exactly the right means to to this kind of trick. But I think you should keep it more simple (KISS) and just make an IAclManager property in the IFileManager and set it to null by default and set the SecurityManager implementation for the cloud service there.
This has different upsides:
You can check if permissions need to be checked by nullchecking the securityManager property. This way, if there doesn't need to be permissionsManaging done (as with localfile system), you don't have exceptions popping up. Like this:
if (fileManager.permissionsManager != null)
fileManager.permissionsManager.addPermission();
When you then carry out the task (to add or delete a file), you can check again if there's a permissionsManager and if the permission is given, if not throw exception (as you'll want to throw the exception when a permission to do an action is missing, not if a permission is missing in general if you're not going to add or delete files).
You can later on implement more IAclManagers for the other IFileManagers when your customer changes the requirements next time the same way as you would now.
Oh, and then you won't have such a confusing hierarchy when somebody else looks at the code ;-)
In general it looks good, but I do have a few suggestions. It seems that your CreateResume() method implementation demands a IFileManager that is also an IAclManager (or else it throws an exception).
If that is the case, you may want to consider adding an overload to your GetManager() method in which you can specify the interface that you require, and the factory can have the code that throws an exception if it doesn't find the right file manager. To accompolish this you can add another interface that is empty but implements both IAclManager and IFileManager:
public interface IAclFileManager : IFileManager, IAclManager {}
And then add the following method to the factory:
public T GetManager<T>(string name){ /* implementation */}
GetManager will throw an exception if the manager with the name given doesn't implement T (you can also check if it derives from or is of type T also).
All that being said, if AddPermissions doesn't take any parameters (not sure if you just did this for the post), why not just call AddPermissions() from CloudFileManager.AddFile() method and have it completely encapsulated from the user (removing the need for the new IAclManager interface)?
In any event, doesn't seem like a good idea to call AddFile in the CreateResume() method and only then throw the exception (since you now you have now created a file without the correct permissions which could be a security issue and also the consumer got an exception so he may assume that AddFile didn't succeed, as opposed to AddPermission).
Good luck!
I've seen this problem come up a lot, but never adequately handled, and I haven't seen it on Stack Overflow, so here goes. I wish there were a way to put this shortly and succinctly without lacking clarity, but I can't seem to shorten it, so bear with me...
A good case-study (my current case, of course) to illustrate the problem follows:
I write code for many locations, a Parent Compary (parentco), and several satellite locations (centers). I have two 'Managers', one designed for the parentco, and one designed for the centers (deployed many times). I also have two libraries, one for the centers, and one generic library (that is used at the centers and the parentco), that programs can include to communicate to the appropriate Manager (via TCP). The library for the centers has several classes designed to wrap database tables and other 'Messages' to do other things, and the generic library has a few 'Messages,' too, such as 'end connection,' 'invoke a process,' and others.
The Question:
When the Manager recieves a Message that is defined in the 'generic' library, how can it know which type of message it is? The first-blush solution would be something like this:
namespace generic_library
{
public interface IMessage_Creator
{
public IMessage Create_Message(short id);
}
public interface IMessage
{
short Message_ID { get; }
}
/// <summary>Perhaps a message to kill the current connection</summary>
public class Generic_Message1 : IMessage
{
public short Message_ID { get { return ID; } }
internal const short ID = 1;
}
public static class Message_Handler
{
private static readonly System.Collections.Generic.List<IMessage_Creator> _creators =
new System.Collections.Generic.List<IMessage_Creator>();
public static void Add_Creator(IMessage_Creator creator)
{
_creators.Add(creator);
}
public static IMessage Get_Message(short id)
{
switch (id)
{//the Generic library knows about the generic messages...
case Generic_Message1.ID:
return new Generic_Message1();
}
//no generic message found, search the registered creators.
IMessage ret = null;
foreach (IMessage_Creator creator in _creators)
{
ret = creator.Create_Message(id);
if (ret != null)
{
return ret;
}
}
//null if no creator was found.
return ret;
}
}
}
namespace center
{
public class Center_Creator : generic_library.IMessage_Creator
{
static Center_Creator()
{
generic_library.Message_Handler.Add_Creator(new Center_Creator());
}
public generic_library.IMessage Create_Message(short id)
{
switch (id)
{//The center library knows about center-specific messages
case center_message1.ID:
return new center_message1();
}
//we return null to say, "I don't know about that message id."
return null;
}
}
public class center_message1 : generic_library.IMessage
{
public short Message_ID
{
get { return ID; }
}
internal const short ID = 2;
}
}
A little explanation. As you can see, the center and generic library have their own messages they can handle. The center interface (here represented by namespace center) registers his creator, Center_Creator, in the static constructor so when the Message_Handler gets a message of his type, the creator will be called on to generate the correct message.
The problem with this approach:
You may have already seen the problem here, and that is:
If the class Center_Creator is never accessed at all (one is never created, and a static method is never invoked) by code, which should be the case until a message of that type is recieved, the static constructor, static Center_Creator() is never invoked, so the Message_Handler never knows about this creator.
That's all fine and dandy, but I don't know how to fix it. Many people have suggested using reflection to invoke the Center_Creator Type Initializer, but I don't want to put that burden on every program that uses this library!
What is the Stack Overflow community's suggestion? Please let me know if I can simplify this to help make it more accessible for the community.
EDIT:
The code is for the generic library and the Center Library. As you can see, I will have the same issues with the Parent Company library.
A diagram of the architecture. http://cid-0676bb3c1f8d6777.office.live.com/self.aspx/Public/Manager.jpg
Image.
Let's break this down:
You have an application which is to send & receive certain types of messages.
A message type must be registered before it can be read, however,
You do not register the type until you send a message, but
You want to be able to read a message before you write one.
Clearly the answer is that you are registering your message types at the wrong time.
I would suggest an explicitly called Init() method for message types. This could be done by using reflection to scan the libraries to see would types are defined, or by manually listing them.
your message handlers can be seen as plugins which makes your problem a potential fit for the Managed Extensibility Framework. Since .Net 4 it's also shipped with the .Net framework.
You can find sample introductions to MEF here and here.
I've put together a litte example to show that it's quite simple to use basic MEF functionality (although there is much more you can do with it). First there is a PluginHost class which will host the plugins in its Plugins collection. Then there's a simple interface containing just the property Description and an example implementation of a plugin called ExamplePlugin.
The Plugins collection will be filled by the container.ComposeParts(..) method called in the constructor. All that's required to make that magic happen are the [Export] and [ImportMany] attributes.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace Playground
{
public class Program
{
static void Main(string[] args)
{
PluginHost host = new PluginHost();
host.PrintListOfPlugins();
Console.ReadKey();
}
}
public class PluginHost
{
[ImportMany]
public IEnumerable<IPlugin> Plugins { get; set; }
public PluginHost()
{
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
public void PrintListOfPlugins()
{
foreach (IPlugin plugin in Plugins)
Console.WriteLine(plugin.Description);
}
}
public interface IPlugin
{
string Description { get; }
}
[Export(typeof(IPlugin))]
public class ExamplePlugin : IPlugin
{
#region IPlugin Members
public string Description
{
get { return "I'm an example plugin!"; }
}
#endregion
}
}
UPDATE: You can use so called Catalogs to discover plugins in more than one assembly. For example there is a DirectoryCatalog which gives you all exports found in all assemblies in a given directory.
AppDomain.CurrentDomain.GetAssemblies(); returns an array of all assemblies loaded into the current AppDomain. You could then iterate over that array to create an AggregateCatalog containing an AssemblyCatalog per loaded assembly.
Some ideas:
Use .NET serialization to serialize/deserialize your messages and put them in a class library used by both ends (or even use WCF to handle communication).
Add a custom attribute to your creator classes and populate the creator list using reflection at the first time Get_Message is called ("if (!initialized) FindAndAddCreators();").
Introduce some initialization method in your library that registers all the creator classes.
Try using a factory pattern.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace SO
{
class Program
{
static void Main(string[] args)
{
MessageFactory factory = new MessageFactory();
IMessage msg = factory.CreateObject(1);
IMessage msg2 = factory.CreateObject(2);
}
}
public interface IMessage
{
short Message_ID { get; }
}
public class Generic_Message1 : IMessage
{
public short Message_ID { get { return ID; } }
internal const short ID = 1;
}
public class center_message1 : IMessage
{
public short Message_ID { get { return ID; } }
internal const short ID = 2;
}
public class MessageFactory
{
private Dictionary<short, Type> messageMap = new Dictionary<short, Type>();
public MessageFactory()
{
Type[] messageTypes = Assembly.GetAssembly(typeof(IMessage)).GetTypes();
foreach (Type messageType in messageTypes)
{
if (!typeof(IMessage).IsAssignableFrom(messageType) || messageType == typeof(IMessage))
{
// messageType is not derived from IMessage
continue;
}
IMessage message = (IMessage)Activator.CreateInstance(messageType);
messageMap.Add(message.Message_ID, messageType);
}
}
public IMessage CreateObject(short Message_ID, params object[] args)
{
return (IMessage)Activator.CreateInstance(messageMap[Message_ID], args);
}
}
}
EDIT to answer comment:
If the "generic" library is the one processing the messages, and it has no knowledge of the types of message is is processing, you obviously have to change that.
Either move to a "plug-in" model where your custom message dlls will be loaded from a specific directory on startup of the generic library, or read the custom message dlls from a config file at startup for the generic library.
// Read customMessageDllName and customMessageClassName from your config file
Assembly assembly = Assembly.Load(customMessageDllName);
IMessage customMessage = (IMessage)assembly.CreateInstance(customMessageClassName);
Why not simply use WCF? You'll get ease of development, great support, as well as interoperability with Java.
Gallactic Jello is on the right path. The part he left out is overcoming the problem of the generic library knowing about classes in the center library, which I have further addressed. I've created a sample solution with three projects, the full contents of which I'll spare you. Here is the gist.
Class Library: Generic lib
Contains a Message_Handler, his own IMessage_Creator, definitions of the interfaces, and an IMessage type of his own.
Class Library: Center Lib
Contains an IMessage_Creator, and his own IMessage type.
Application: Application
has a SVM (static void Main()) containing the following lines of code:
Generic_lib.IMessage msg = Generic_lib.Message_Handler.get_message(2); //a Center Message
if (msg is Center_lib.Center_Message)
{
System.Console.WriteLine("got center message");
}
You will be amazed how important the if statement is!!! I'll explain later
Here's the code in the Type Initializer for Generic_lib.Message_Handler:
static Message_Handler()
{
//here, do the registration.
int registered = 0;
System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (System.Reflection.Assembly asm in assemblies)
{
System.Type[] types = asm.GetTypes();
foreach (System.Type t in types)
{
System.Type[] interfaces = t.GetInterfaces();
foreach (System.Type i in interfaces)
{
if (i == typeof(IMessage_Creator))
{
System.Reflection.ConstructorInfo[] constructors = t.GetConstructors();
foreach (System.Reflection.ConstructorInfo ctor in constructors)
{
if (ctor.GetParameters().Length == 0)
{
Add_Creator(ctor.Invoke(new object[0]) as IMessage_Creator);
registered++;
}
}
}
}
}
}
System.Diagnostics.Debug.WriteLine("registered " + registered.ToString() + " message creators.");
}
Horrific, isn't it? First, we get all the assemblies in the current domain, and here's where the if statement comes in. If there was no reference to the 'Center__lib' anywhere in the program, the array of Assemblies won't contain Center_lib. You need to be sure that your reference to it is good. Creating a method that is never called that references it is not enough, a using statement is not good enough,
if (msg is Center_lib.Center_Message) ;
is not enough. It has to be a reference that can't be optimized away. The above are all optimized away (even in Debug mode, specifying `don't optimize.'
I hope someone can come up with an even more elegant solution, but this will have to do for now.
Aaron