Click here to Skip to main content
15,881,204 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more: , +
I have an existing C# console application that takes arguments and based on the arguments creates an instance of markets (UK, US, MX..) using dependency injection.

Each market class does a 'string GetData()', 'string ProcessData()' and 'bool ExportData()'.

The application was initially created for one eCommerce vendor's markets. Now I am told to modify it for a different vendor that does a different process. The high-level flow remains the same.

'GetData' to fetch records from DB,
'ProcessData' for any transformation or the likes
'ExportData'.

The difference is Getdata() pulls records from DB and maps to an object. I am planning to use Petapoco. 'ProcessData' might return a similar class. 'Exportdata' currently does an API call but for the new vendor, I have to write to a file.

I was reading up on patterns I am totally confused. At first, I thought I needed abstract factory pattern and now I think the factory method is what I should be using but I am not sure if I am doing it right. Need some guidance/review here. A sample cs file I created from my understanding of factory pattern. This code is based on the headfirst code samples.

Do you think this is the right design approach?

I also want to keep the console project independent of vendor project. So maybe 'StatusExport.Program' for the console application. DLL projects StatusExport.Common to hold the interface and abstract classes' and 'StatusExport.Client(ex:StatusExport.Costco)' for each vendor stuff.

What I have tried:

using System;
using System.Collections.Generic;
using StatusExport.Models;

namespace factorymethod
{
    class Program
    {
        static void Main(string[] args)
        {
            ClientFactory factory = null;
            Console.WriteLine("Enter client code:");
            string clientCode= Console.ReadLine();
            switch (clientCode.ToLower())
            {
                case "costco":
                    factory = new CostcoFactory("accountname", "taskname");
                    break;
                    //NEw vendor might be added
                    //case "walmart"
                    //factory = new WalmartFactory("taskname", "type");
                    //break
                default:
                    break;
            }

            bool status = factory.ProcessData();
            Console.ReadKey();
        }
    }

    abstract class Client
    {
        public abstract string AccountName { get; }
        public abstract string Task { get; set; }
        //More properties might be added. Some may not even be used by some of the new vendors. For example, Costco Might need accountname and task. Tomorrow if walmart comes, they might not need these two or may need task and a new property 'type'
        public abstract List<T> GetData<T>();
        public abstract List<T> ProcessData<T>();
        public abstract bool ExportData();
    }


    class CostcoClient : Client
    {
        public override string AccountName { get; }
        public override string Task { get; set; }

        public CostcoClient(string accountName, string task)
        {
            AccountName = accountName;
            Task = task;
        }

        public override List<DBRecord> GetData<DBRecord>() //DBRecord class is specific to Costco. 
        {
            List<DBRecord> dbresult = new List<DBRecord>();
            //dbresult = db return data mapped to an object DBRecord using petapoco. Another vendor might have a different class to which DB records are mapped. So the return type can be generic
            return asn;
        }

        public override List<T> ProcessData<T>()
        {
            throw new NotImplementedException(); //Any data transformation or business logic. Return type might be DBRecord or a new class altogether
        }

        public override bool ExportData()
        {
            throw new NotImplementedException();//Call API or write data to file and if success send true else false
        }
    }

    abstract class ClientFactory
    {
        public abstract bool ProcessData();
    }


    class CostcoFactory : ClientFactory
    {
        public string AccountName { get; }
        public string Task { get; set; }
        public CostcoFactory(string accountname, string task)
        {
            AccountName = accountname;
            Task = task;
        }

        public override bool ProcessData()
        {
            CostcoClient gc = new CostcoClient(AccountName, Task);
            var result = gc.GetData<DBRecord>();
            return true;
        }
    }
}
Posted
Updated 28-May-20 23:52pm
Comments
[no name] 28-May-20 15:29pm    
Look at "Interfaces" instead of abstract classes. In this case, your abstract Client class buys you nothing. in particular, you have "abstract" properties that don't need to be abstract, creating redundant override code.

1 solution

You can find a nice overview with examples here: .NET Design Patterns in C# and VB.NET - Gang of Four (GOF) - doFactory.com[^]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900