[当我们拥有具有类似高级功能的类但在方法中返回不同类型的类时使用哪种设计模式?

问题描述 投票:0回答:1

我有一个现有的C#控制台应用程序,该应用程序接受参数并基于参数使用依赖项注入创建市场实例(英国,美国,MX ..)。

每个市场类都执行'string GetData()','string ProcessData()'和'bool ExportData()'。

该应用程序最初是为一个电子商务供应商的市场创建的。现在,我被告知为执行不同过程的其他供应商修改它。高级流程保持不变。

  1. 'GetData'从数据库中获取记录,
  2. 'ProcessData'用于任何转换或类似操作
  3. 'ExportData'。

不同之处在于Getdata()从数据库中提取记录并映射到一个对象。我打算使用Petapoco。 'ProcessData'可能返回类似的类。 “ Exportdata”当前正在执行API调用,但是对于新供应商,我必须写入文件。

我正在阅读我完全困惑的模式。起初,我以为我需要抽象的工厂模式,现在我认为工厂方法就是我应该使用的方法,但是我不确定我是否做对了。在这里需要一些指导/评论。我根据对工厂模式的了解创建了一个示例CS文件。该代码基于headfirst代码示例。

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;
        }
    }
}

您认为这是正确的设计方法吗?

我还希望使控制台项目独立于供应商项目。因此,对于控制台应用程序,可能是“ StatusExport.Program”。 DLL计划StatusExport.Common来保存每个供应商的接口和抽象类和“ StatusExport.Client(ex:StatusExport.Costco)”。

c# .net design-patterns dependency-injection factory-pattern
1个回答
0
投票

您可以创建将包含一组基本属性的BaseClient类,如果需要添加一些新内容-只需继承它即可。您做对了,但我认为最好在属性AccountNameTask中将public修饰符更改为protected,以便仅从子类访问它们。实际上,如果不确定返回类型List是否总是实际的,则可以为每个方法创建BaseClientModels(请求/响应)。示例:

public abstract class BaseClient
{
    #region Properties : Protected

    protected abstract string AccountName { get; }

    protected abstract string Task { get; set; }

    #endregion

    #region Methods : Public

    public abstract BaseGetDataResponseModel GetData(BaseGetDataRequestModel model);

    public abstract BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model);

    public abstract BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model);

    #endregion
}

public class BaseGetDataResponseModel { }

public class BaseGetDataRequestModel { }

public class BaseProcessDataResponseModel { }

public class BaseProcessDataRequestModel { }

public class BaseExportDataResponseModel { }

public class BaseExportDataRequestModel { }

然后让我们看看您的类CostcoClient以及它的外观:

public class CostcoClient : BaseClient
{
    #region Properties : Protected

    protected override string AccountName { get; }

    protected override string Task { get; set; }

    protected virtual IDataReader<BaseGetDataRequestModel, BaseGetDataResponseModel> DataReader { get; }

    protected virtual IDataProcessor<CostcoClientProcessDataRequestModel, CostcoClientProcessDataResponseModel> DataProcessor { get; }

    protected virtual IExportDataHandler<CostcoClientExportDataRequestModel, CostcoClientExportDataResponseModel> ExportDataHandler { get; }

    #endregion

    #region Constructors

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

    #endregion

    #region Methods : Public

    public override BaseGetDataResponseModel GetData(BaseGetDataRequestModel model)
    {
        if (model is CostcoClientGetDataRequestModel clientGetDataRequestModel)
        {
            return DataReader.ReadData(clientGetDataRequestModel);
        }
        return null; //wrong type has passed
    }

    public override BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model)
    {
        if (model is CostcoClientProcessDataRequestModel clientProcessDataRequestModel)
        {
            return DataProcessor.ProcessData(clientProcessDataRequestModel);
        }
        return null;
    }

    public override BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model)
    {
        if (model is CostcoClientExportDataRequestModel clientExportDataRequestModel)
        {
            return ExportDataHandler.Handle(clientExportDataRequestModel);
        }
        return null;
    }

    #endregion
}


public class CostcoClientGetDataRequestModel : BaseGetDataRequestModel { }

public class CostcoClientGetDataResponseModel : BaseGetDataResponseModel { }

public class CostcoClientProcessDataRequestModel : BaseProcessDataRequestModel { }

public class CostcoClientProcessDataResponseModel : BaseProcessDataResponseModel { }

public class CostcoClientExportDataRequestModel : BaseExportDataRequestModel { }

public class CostcoClientExportDataResponseModel : BaseExportDataResponseModel { }

public interface IDataReader<TIn, TOut>
{
    public TOut ReadData(TIn model);
}

public interface IDataProcessor<TIn, TOut>
{
    public TOut ProcessData(TIn model);
}

public interface IExportDataHandler<TIn, TOut>
{
    public TOut Handle(TIn model);
}

public class CostcoClientDataReader : IDataReader<CostcoClientGetDataRequestModel, CostcoClientGetDataResponseModel>
{
    public CostcoClientGetDataResponseModel ReadData(CostcoClientGetDataRequestModel model)
    {
        throw new NotImplementedException();
    }
}

    //and so on

IDataReaderIDataProcessorIExportDataHandler中,您可以制作逻辑并从GetDataProcessDataExportData方法中调用它,例如,并通过依赖注入获得实例。

然后,我们可以将您的工厂更改为此:

public interface IClientFactory
{
    BaseClient GetClientService(ClientServicesEnum value);
}


public class BaseClientFactory : IClientFactory
{
    #region Propertied : Protected

    protected virtual IEnumerable<BaseClient> Services { get; }

    protected string AccountName { get; }

    protected string Task { get; set; }

    #endregion

    #region Constructors

    public BaseClientFactory(IEnumerable<BaseClient> services, string accountname, string task)
    {
        Services = services;
        AccountName = accountname;
        Task = task;
    }

    #endregion

    public BaseClient GetClientService(ClientServicesEnum value)
        => Services.First(x => x.GetType().Equals(GetClientServiceByCode()[value]));

    private Dictionary<ClientServicesEnum, Type> GetClientServiceByCode()
        => new Dictionary<ClientServicesEnum, Type>()
        {
            { ClientServicesEnum.CostcoClient, typeof(CostcoClient) }
        };

}

public enum ClientServicesEnum
{
    CostcoClient = 1,
    Another2 = 2,
    Another3 = 3
}

哪里

protected virtual IEnumerable<BaseClient> Services { get; }

您也可以通过DI获取,然后通过枚举获取正确的ServiceHandler。

以及您用来调用所有这些的主要功能:

        switch (clientCode)
        {
            case 1:
                baseClient = ClientFactory.GetClientService(ClientServicesEnum.CostcoClient);
                break;
            case 2:
                baseClient = ClientFactory.GetClientService(ClientServicesEnum.Another2);
                break;
            default:
                break;
        }

        bool status = baseClient.ProcessData(null); //your model
© www.soinside.com 2019 - 2024. All rights reserved.