Factory to return array of IItem from single object

310 Views Asked by At

This is a simplified version of the problem i am solving but conceptually equivalent. This project is using castle windsor and I am trying to keep all factories in the container.

I have a single object that represents data parsed from a text file. After parsing this file I need to write a new text file with 2 line based on data in the original object.

lets say the text file is Some Person, Work Phone, Mobil Phone

this gets parsed into

    public class Person
    {
        public string Name{get;set;}
        public stirng WorkPhone {get;set;}
        public stirng MobilPhone {get;set;}
    }

Now this is a simplified example so keep that in mind please. The next step is to creat new object instances that represent each line we will write to the text file

    public interface IFileEntry
    {
        string Name{get;set;}
        string Number{get;set;}
    }

    public class PersonWorkPhoneEntry : IFileEntry
    {
        public string Name {get;set;}
        public string Number{get;set;}
        public override ToString(){....}
    }

    public class PersonMobilPhoneEntry: IFileEntry
    {
        public string Name{get;set;}
        public string Number{get;set;}
        public override ToString(){....}
    }

so being that we are using Castle for this lets make a factory

    public interface IFileEntryFactory
    {
        IFileEntry Create(string entryType, stirng Name, string Number
    }

I have created my own implementation for the DefaultTypedFactoryComponentSelector and install that for this factory only.

    public class FileEntryComponentSelector : DefaultTypedFactoryComponentSelector
    {
        protected override string GetComponentName(System.Reflection.MethodInfo method, object[] arguments)
        {
            if (method.Name == "Create" && arguments.length == 3)
            {
                return (string)arguments[0];
            }

            return base.GetComponentName(method, arguments);
        }
    }

This works,

    var workEntry = _factory.Create("PersonWorkPhoneEntry", person.Name, person.WorkPhone)
    var mobilEntry = _factory.Create("PersonMobilPhoneEntry", person.Name, person.WorkPhone)
    //then write the tostring to a text file

Sorry for the long setup but i think its needed. What I am trying to do Is

    public interface IFileEntryFactory
    {
        IFileEntry Create(string entryType, stirng Name, string Number
        IFileEntry[] Create(Person person)
    }

    var entries = _factory.Create(person);
    foreach(var e in entries)
    ///write to text file.

I have been digging all over for a solution like this with no results. What seems to be a possible solution taking the example shown here (Castle Windsor Typed Factory Facility with generics) Im currently working on implementing something like this now, not sure if this is the right way to solve this problem.

The questions:

  • are there any other ways to have the factory return the array of needed objects
  • what is the best practice for solving something like this
  • any examples and reading for advanced factories
1

There are 1 best solutions below

1
On BEST ANSWER

It is possible to make a Factory return to you an array of objects which are already registered in the container. Here is an example

  container.Register(Component.For<IMyStuffProvider>().AsFactory()) // registration

  public interface IStuffProvider
  {
     IEnumerable<IMyStuff> GetAllStuff();
     void Release(IMyStuff stuff);
  }

This code makes possible that every registered implementation of IMyStuff gets returned by the factory.

But I think that your problem is different : you are using the factory for the wrong purpose. TypedFactory is to get instances of objects that are already registered in the container during app start and not to manipulate files. Their purpose is to solve problems regarding dependencies.

If you are parsing a csv/txt into objects and then writing some of the rows back into another csv/txt you have to make

  1. IFileEntryManager (with an implementation) with a methods like DeserializeFileToObjects, WriteObjectsToFile, etc.
  2. IFileEntryManagerFactory to create and return IFileEntryManager. ( Castle typed factory here :) )
  3. Now inject your IFileEntryManagerFactory in your ctor of the class that needs to serialize/deserialize text files and and use it to get your FileEntryManager which in turn will act upon your text files.

If you have different objects like Person, Company, Employee... etc. and you want to handle them with generic manipulator - it is ok. The best way is to implement a Generic Repository. Lets say ICsvRepository<T>. Just search for 'Generic Rpository in c#' and ignore that fact that most of the implementation examples are with EntityFramework as a persistence store. Behind the interface you can make it read/write to csv rather than to DB.

Lets generalize it. If you have to deal with resources - files, sql, blobs, tables, message bus or whatever resource persistent/non persistent which comes in or goes out of your application you have to manipulate it through an abstraction IMyResourceManager with its corresponding manipulation methods. If you have several implementations of IMyResourceManager and you want to decide during runtime which implementation you want then you have to make IMyResourceManagerFactory with a component selector or factory method and place your differentiation logic there.

That is why I think you do not need a TypedFactory for text file read/write but a pure ITextFileManipulator which you have to register in the container and get it through constructor. You may need a typed factory if you go for ICsvRepository<T> where T is your Person class. Inside the implementation of ICsvRepository<T> you will need ICsvFileManipulator.