处理继承类中参数的最佳方法

3
我有一个基类ExportType和几个继承类,实现了特定的数据导出。
继承类需要多个参数来定义从数据库导出数据的方式。这些参数可能因类而异。
所以我想使用Dictionary<string, string>来处理导出参数,在我的基类中我添加了一个方法,如下所示:
public abstract void Export (Dictionary<string, string> exportParams);

这是最好的处理方式吗?还是有更好的方法来处理不同的参数?


2
为什么不创建一个ConfigParamters类,并将其对象作为参数传递? - Shoaib Shaikh
1
即使所有子类的导出策略逻辑都不同,还是相同的吗? 如果相同,则让基类处理逻辑并使属性虚拟,接受这些参数对于不同的子类是不同的。 - Zenwalker
1
是的,您可以将参数封装在一个类中。正如@zenwalker所说,如果您想创建更具体的参数配置,可以使用继承。 - Shoaib Shaikh
@anatoliiG 参数数量可能会有所不同...有些类不需要任何参数,而其他一些类需要10个或更多的参数... - davioooh
它可能是什么类型的参数(布尔型,整型,小数等)? - Anatolii Gabuza
显示剩余4条评论
2个回答

4

由于您无法确定特定导出类型需要哪些参数,因此您有几个选择:

  1. 使用字典(就像您提出的那样):可扩展性强,但没有类型安全性
  2. 为接口使用基类:仍然没有类型安全性,因为您需要在每个特定的导出方法内部进行强制转换。
  3. 使参数实现特定且对调用方隐藏:我认为这是首选。

如果通过多态来隐藏导出的具体实现,则不应该期望他们了解您的内部参数。

我会简化您的导出界面:

interface IExport 
{
    void Export(); // or Export(string filename), alternatively
}

然后根据需要实例化每个具体类:

// no params
IExport txt = new TextExport();

// single string (delimiter)
IExport csv = new DelimitedExport(",");

// lots of params
IExport excel = new ExcelExport(someStronglyTypedOptions);

通过这种方法,您的调用代码就不需要担心传递这些参数。

[编辑]

总之,通过重写以下内容,您可以轻松解决参数类型的问题,而没有其他明显的好处:

var csv = new ExcelExport();
csv.Export(parameters);

转换为:

var csv = new ExcelExport(parameters);
csv.Export();

在某一时刻,某个人需要知道要实例化哪些参数以及如何做到这一点。这意味着从那一点开始,其他所有人都可以接受一个IExport实例,并且除了调用一个普通的无参数方法外,不允许进行任何操作。

您的具体实现将会有不同的构造函数,并且通常会遵循这种模式:

class ExcelExport : IExport
{
    private readonly ExcelParams _params;
    public ExcelExport(ExcelParams parameters)
    {
        _params = parameters;
    }

    public void Export() 
    {
        // do stuff
    }
}

这可能是一个好主意,但对我来说不起作用。在我的情况下,每个特定导出类的“Export”方法可以被调用多次,传递不同(特定)参数,以获得该特定类型的不同报告...希望我的解释清楚... - davioooh
@DavidC.:对于每个新的参数集,您只需创建一个新实例(通过构造函数传递参数),但是要在调用堆栈中更早或在工厂方法内部执行此操作。本质上是相同的,但实际实现的概念可以对调用者隐藏。这种方法的想法(以及接口的通常想法)是使 IExport 公开,提供公共的 ExportFactory,但隐藏所有具体实现以使它们无法访问。 - vgru
@DavidC.:如果您不采用这种方式,让调用者实例化不同的参数类型,那么您最好为每个“Export”方法命名不同的名称;您的调用者显然知道它正在处理哪个具体实现。但这并不意味着基于字典的方法是错误的,它只是稍微不太安全且容易出现运行时错误。 - vgru
我完全同意你的方法,我认为这是最好的想法,但我对工厂模式并不是很有经验,所以我正在尝试想象如何将你的解决方案适应我的问题... - davioooh
@DavidC.:我已经更新了我的答案。你实例化导出类的地方基本上就是你的工厂,这也是通常将参数注入到具体实例中的地方。 - vgru
好的,我会尝试应用你的建议。非常感谢! :) - davioooh

2

根据它的称呼,您可能能够使基类成为通用的,接受您创建的参数类的类型。

public abstract class BaseClass<TExportParams>
{
    public abstract void Export(TExportParams exportParams);
}

public class Derived : BaseClass<DerivedExportParamsClass>
{
    public void Export(DerivedExportParamsClass exportParams)
    {

    }
}

如果您不知道在调用Export时要传递的参数类型,请参考@Groo的答案。

我同意创建一个ExportModel基类来使用,然后从该基类继承每个特定所需值的自己的类ExportWidgetDataClass。 - Andy Stannard
1
这个解决方案可能已经足够了 - 主要的缺点是,你不能拥有例如 List<BaseClass <?>> 这样的混合列表(其中 ?Params1Class Params2Class),除非你引入 BaseClass 并使其成为 BaseClass<T> 的超类。即使如此,你也无法公开 Export(T t),因为你在基类中缺少泛型。所以你将不得不添加 Export(object obj) 并在具体实现中进行类型转换... - user57508

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接