微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

开闭原则 - 如何使用提供者的参数进行重构

如何解决开闭原则 - 如何使用提供者的参数进行重构

我正在处理一些似乎违反开闭原则的旧版 dotnet 框架 4.7 代码。报表类做几乎相同的事情:从数据库获取一些项目,运行一些转换并在 GetItems 方法中返回它们。我被要求添加一个报告,但这意味着更改不断增长的 ReportManager 类。报告需要不同的参数,这让我很难看到我该如何前进。 我该如何重构它,使其不会破坏 SOLID 中的 O?

更新

在两个报告中都添加了对 GetItems() 的缺失调用,以及对 _repository 的调用


public interface IReport
{
    string GetItems();
}

public class StoreItemsReport : IReport
{
    private readonly int[] _numbers;
    private readonly IRepository _repository;
    public StoreItemsReport(IRepository repo,int[] numbers)
    {
        this._repository = repo;
        this._numbers = numbers;
    }
    public string GetItems()
    {
        return _repository.GetStoreItems(numbers);
    }
}

public class OnlineItemsReport : IReport
{
    private readonly string _account;
    private readonly IRepository _repository;
    public OnlineItemsReport(IRepository repo,string account)
    {
        this._repository = repo;
        this._account = account;
    }
    public string GetItems()
    {
        return _repository.GetonlineItems(account);
    }
}

public class ReportManager
{
    private readonly IRepository repository;
    public ReportManager(IRepository repository)
    {
        this.repository = repository;
    }
    public void HandlesupplierItems(int[] numbers)
    {
        var items = new StoreItemsReport(repository,numbers).GetItems();
        Utils.SendData("storeitems-url",items);
        Emailer.SendReport(items);
    }

    public void HandleStoreItems(string account)
    {
        var items = new OnlineItemsReport(repository,account).GetItems();
        Utils.SendData("onlineitems-url",items);
        Emailer.SendReport(items);
    }

    // and so on
}

// I would like to do something like this,but how do I add arguments to the providers
var provider = providerFactory.GetProvider("suppliers");
var items = provider.GetItems();
Utils.SendData("url",items);
Emailer.SendReport(items);

解决方法

您可以让您的 ReportManager 接受工厂方法:

public class ReportManager
{
    private readonly IRepository repository;
    public ReportManager(IRepository repository)
    {
        this.repository = repository;
    }

    public void HandleItems(Func<IRepository,IReport> factory,string url)
    {
        var items = factory(repository).GetItems();
        Utils.SendData(url,items);
        Emailer.SendReport(items);
    }
}

可以这样使用:

var numbers = new[] { 1,2,3 };
reportManager.HandleItems(repo => new StoreItemsReport(repo,numbers),"storeitems-url");
,

如果您将 IRepository 设为 IReport 接口的公共属性,您只需为 IReport 提供一个新的 ReportManager 实例:

public interface IReport
{
    string GetItems();
    IRepository Repository {get;set;}
    string InfoString {get;}
}

public class StoreItemsReport : IReport
{
    private readonly int[] _numbers;
    public IRepository Repository {get;set;}
    public InfoString => "storeitems-url";
    public StoreItemsReport(int[] numbers)
    {
        this._numbers = numbers;
    }
    public string GetItems()
    {
        return Repository.GetOnlineItems(account);
    }
}

public class OnlineItemsReport : IReport
{
    private readonly string _account;
    public IRepository Repository {get;set;}
    public InfoString => "onlineitems-url";
    public OnlineItemsReport(string account)
    {
        this._account = account;
    }
    public string GetItems()
    {
        return Repository.GetStoreItems(numbers);
    }
}

public class ReportManager
{
    private readonly IRepository repository;
    public ReportManager(IRepository repository)
    {
        this.repository = repository;
    }
    public void HandleItems(IReport report)
    {
        report.Repository = repository;
        var items = report.GetItems();
        Utils.SendData(report.InfoString,items);
        Emailer.SendReport(items);
    }
}

用法是

var report = new OnlineItemsReport("test");
reportManager.HandleItems(report);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。