Architectural/best-practices question about generics - c#

I'm working my way through 'head first design patterns' and want to use this in practice immediately.
I'm writing a piece of code that connects an application with other applications. In fact, I need to generate an e-mail containing an XML file and send it via e-mail. But other stuff might be required in the future.
Thus, I identified 'the things that change':
- The data for the transmission
- The means of transmitting (could be e-mail, but could be FTP or webservice for another data-exchange)
So, I:
- Created an abstract class DataObject
- Created an interface ITransmissionMethod
- Created an dataExchange abstract class:
abstract class DataExchange<T,U>
{
private T DataObject;
private U SendMethod;
}
And SendViaMail is like
class SendViaMail : ISendMethod<System.Net.Mail.Attachment>
{
public override void Send(System.Net.Mail.Attachment dataItem)
{
throw new NotImplementedException();
}
}
Now - I can create classes like:
class MyExchange : DataExchange<MyDataObject,SendViaMail> { }
What do you think about this approach? Now what I would really like to do is Create an abstract method in DataExchange that should look something like
private abstract [the type of the T in ISendMethod<T>] PrepareObjectForSending(T dataObject) {
}
Visual Studio would force me to implement a method like:
private abstract System.Net.Mail.Attachment PrepareObjectForSendingMyDataObject dataObject) {
// Serialize XML file and make it into attachment object
}
Wouldn't that be sweet? But what do you guys think about this approach? In the future, people can create new dataObjects and new sendmethods and the code would still work. What I've been trying to do is: program against interface and extract changing parts. How about it?

That would work, but you could separate concerns even more. Here is just another version - make DataExchange to be very simple and delegate real work to workers:
class DataExchange<TDataObject, TTransmissionObject>
{
IConverter<TDataObject, TTransmissionObject> conterver;
ISendMethod<TTransmissionObject> sender;
public Send(TDataObject dataObject)
{
TTransmissionObject tro = conterver.Convert(dataObject);
sender.Send(tro);
}
}
Converts would just convert data objects to objects suitable for transmission:
class DataToAttachmentConverter : IConverter<DataObject, Attachment>
{
Attachment Convert(DataObject) { }
}
class DataToXmlConverter : IConverter<DataObject, XmlDocument>
{
XmlDocument Convert(DataObject) { }
}
Senders would only send.
class MailSender : ISendMethod<Attachment>
{
void Send(Attachment) {}
}
class FtpPublisher : ISendMethod<XmlDocument>
{
void Send(XmlDocument) {}
}
Putting all together:
var exchanges = new [] {
new DataExchange<DataObject, Attachment>( new DataToAttachmentConverter(), new MailSender()),
new DataExchange<DataObject, XmlDocument>( new DataToXmlConverter(), new FtpPublisher())
};
foreach(var ex in exchanges)
ex.Send(dataObject); //send as an attachent and put to ftp site.

Related

Refactoring to make code open for extensions but closed for modifications

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 => ....);
}
}

Marten: Define schema stuff (like indexes etc) not in the constructor/factory call to create the DocumentStore

I just started testing Marten (2.9), and so far I am loving it. However, I am not sure I am following the DocumentStore.For method. For example, in my "dbhandler" for Marten, I can write:
public MartenDbHandler()
{
store = DocumentStore.For(_ =>
{
_.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate;
_.Connection("host=localhost;database=marten;password=root;username=postgres");
_.Schema.For<Customer>().Index(x => x.PopulationRegistryNumber);
});
}
but naturally, I do not want to have all that schema code when I initialize the database and supply the connection string.
So I thought, maybe I can pass on the store variable, and do the same, but then the For thing doesn't exist:
... and I haven't really found a way to set the Schema in any other way.
What I really want to do is to have an Interface, that is dynamically loaded and executed (via Reflection) when I start my application, that handles those things, like an IMartenMetaData that looks something like:
public interface IMartenMetaData
{
SetMetaData(DocumentStore store);
}
and then implement the schema things in that/those classes, but that doesn't work because I can't use the DocumentStore to set the meta.
Keep it simple. The document store is supposed to have a single instance in your app and you define the schema properties during construction. No need to abstract the store.
One way is you can create your own implementation of DocumentStore. You can refer to the test document store classes in the source code.
Update:
You can find the sample here https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/TestingDocumentStore.cs
I managed to do a much nice approach to keep it more dynamic and not all in the construction of DocumentStore.
Please see code below. The idea is straightforward:
Create the StoreOptions separately
Before creation of the DocumentStore, run method that via Reflection finds all classes of a certain Type that will add table meta data
Create the DocumentStore
public MartenDbHandler()
{
StoreOptions so = new StoreOptions();
so.Connection("host=localhost;database=marten;password=root;username=postgres");
so.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate;
SetTableMeta(so);
store = new DocumentStore(so);
}
private void SetTableMeta(StoreOptions storeOptions)
{
// We get the current assembly through the current class
var currentAssembly = Assembly.GetExecutingAssembly();
// we filter the defined classes according to the interfaces they implement
var stuff = currentAssembly.DefinedTypes.Where(type => type.IsSubclassOf(typeof(MartenTableMetaDataBase))).ToList();
foreach (Type type in stuff)
{
IMartenTableMetaData temp = (IMartenTableMetaData)Activator.CreateInstance(type);
temp.SetTableMetaData(storeOptions);
}
OnLogEvent?.Invoke(this, $"{stuff.Count} table meta data initialized");
}
The IMartenTableMetaData is a base class for the IMartenTableMetaData interface. In the example below, the base class isn't used, but I normally find it good to have a base class (I use a similar approach to another ORM, where I actually use the base class). But, the base class can of course be removed if you have no use for it.
internal abstract class MartenTableMetaDataBase : IMartenTableMetaData
{
public void SetTableMetaData(StoreOptions storeOptions)
{
SetSpecificTableMetaData(storeOptions);
}
protected abstract void SetSpecificTableMetaData(StoreOptions storeOptions);
}
and the interface:
public interface IMartenTableMetaData
{
void SetTableMetaData(StoreOptions storeOptions);
}
So, I can now create a class for each Type I want to add meta data too, like this:
internal class MartenTableMetaDataCustomer : MartenTableMetaDataBase
{
protected override void SetSpecificTableMetaData(StoreOptions storeOptions)
{
storeOptions.Schema.For<Customer>().Index(x => x.Muni);
}
}
or
internal class MartenTableMetaDataDriver : MartenTableMetaDataBase
{
protected override void SetSpecificTableMetaData(StoreOptions storeOptions)
{
storeOptions.Schema.For<Driver>().Index(x => x.Username);
}
}
etc.
This will keep the Marten DB handler clean and meta data separated into specific classes for readability, clarity and all that stuff =)

How to send Class type to another class and create instance of this class?

I'm working on library that will help implement dedicated servers for all sorts of applications (mainly my goal is games). I'm working with sockets and I want to implement some sort of command system, where users will be able to invoke functions on the server.
I have a problem because I wanna let a user implement interactable command environment in a class created by him that my library will need to know about.
I created this template example of how it's all structured:
Implemented by me, part of library (very simplified):
public class UserInfo //class containing info about user
{
public int id;
public UserInfo(int _id)
{
id = _id;
}
}
public class UserManager
{
List<UserInfo> userInfos;
public UserManager(List<UserInfo> _userInfos) //We get out infos from somewhere...
{
userInfos = _userInfos; //...and keep reference to them
//SetupChildClassAndInfos();
}
//I'd like to have something like that BUT I don't know
//how ChildClass is called so I can't just type it like here
/*
List<ChildClass> childs = new List<ChildClass>();
void SetupChildClassAndInfos()
{
foreach (var userInfo in userInfos)
{
ChildClass child = new ChildClass();
child.someInfo = userInfo;
childs.Add(child);
}
}
*/
//I tried working with generics but failed miserably xd
List<T> childs = new List<T>();
public void GetChildClass<T>()
{
foreach (var userInfo in userInfos)
{
T child = new T();
child.userInfo = userInfo;
childs.Add(child);
}
}
//of course it doesn't work and makes no sense xD but I hope you kinda g
//get what I'm trying to accomplish
}
public class UserClass //Base class for further implementation containing
//userInfo that user needs to know about
{
public UserInfo userInfo;
}
Example implementation by someone else, I don't know how ChildClass will be called:
public class ChildClass : UserClass //there needs to be access to UserClass informations
{
CustomManager customManager;
[Command] //attribute making method be called automaticly when is the right time
public void Message(string _message) //A method made by a user BUT(!) he will never use it directly
{
customManager.ReceiveMessage(userInfo.id, _message);
}
}
public class CustomManager
{
UserManager userManager; //assume we somehow have reference
public CustomManager()
{
userManager.GetChildClass<ChildClass>(); //sending information in beginning to infoManager how I implemented my ChildClass (doesn't work)
}
public void ReceiveMessage(int _id, string _message)
{
Debug.Log("We got message: " + _message + " from user with id: " + _id);
}
}
So my question is how do I send a custom made class to UserManager and create instances of this class?
Maybe what I'm writing just doesn't make any sense and my aproach is stupid, feel free to criticize.
Make CustomManager a generic class
Generic Property in C#
OR
Use dependency injection via implementing the dependency inversion principal using spring.net or Unity framework.
What's wrong with having just a dictionary IReadOnlyDictionary<string, object>? Are you concerned with boxing of value types? A glimpse on your code convinces me that it's too early to proceed on more sophisticated solutions. So it makes sense to abstract out this piece into an interface and implement that one in a simplest possible way: with help of dictionaries (a-ka JavaScript way).

Sharing data between classes when only knowing the interface they implement

I am writing an application that will export a bunch of data from a database into files with specific file structures. There is only one 'type' of export defined so far but there will be more so I want to make it easy for new 'types' to be plugged in.
I have defined the following interface that all export 'types' must implement:
public interface IExportService
{
ExportType ExportType { get; set; }
Task DoExport(Store store);
}
The ExportType is an enum and the Store object is a customer ( rather than a data store of some kind ).
So far there is only one class that implements this interface : RetailExportService.
public class RetailExportService : IExportService
{
public ExportType Type
{
get { return ExportType.Retail; }
}
public async Task DoExport(Store store)
{
List<IRetailExport> retailExports = GetRetailExportFiles();
foreach (var retailExport in retailExports)
{
await retailExport.Export(store);
}
}
private List<IRetailExport> GetRetailExportFiles()
{
return (from t in Assembly.GetExecutingAssembly().GetTypes()
where t.GetInterfaces().Contains(typeof(IRetailExport))
select Activator.CreateInstance(t) as IRetailExport).ToList();
}
}
This class loops through all IRetailExport interfaces in the assembly and calls it's Export method. The actual querying of data and creation of files is done in the Export method.
public interface IRetailExport
{
String FileName { get; }
Task Export(Store store);
}
So, if a new file must be created I can just create a new class that implements IRetailExport and this will automatically be called by the application.
The problem I have is that I have 13 classes that implement IRetailExport and 5 of these classes require the same data. At the moment I am querying the database in each of the classes but this is a bad idea and slows down the application.
The only way I can think of doing this is to define an interface like so:
public interface IDataRequired<T> where T: class
{
IEnumerable<T> Data { get; set; }
}
and have the classes the require the same data implement this class. In the DoExport() method I can then check if this class implements IDataRequired - if so, populate the Data property:
public async Task DoExport(Store store)
{
List<IRetailExport> retailExports = GetRetailExportFiles();
List<ExpRmProductIndex> requiredData = await GetIndexedProductList(store.Id);
foreach (var retailExport in retailExports)
{
if (retailExport is IDataRequired<ExpRmProductIndex>)
(retailExport as IDataRequired<ExpRmProductIndex>).Data = requiredData;
await retailExport.Export(store);
}
}
However, I don't think this is a very elegant solution so I was hoping someone here could suggest a better way of approaching this ? Thanks !!
Reading from or writing to many files in parallel tasks is not a good idea, as this makes the disk head jump many times between the files what causes delays. (I assume that this happens if you have an await in a loop.)
Instead, process one file after the other in a strict sequential order and await once for the whole process to complete.

Some design-pattern suggestions needed

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!)

Categories