如何重构此代码以将更多方法实现移动到基类中?

时间:2018-05-23 20:46:33

标签: c# .net

假设我有以下内容:

图书馆计划

interface IDoStuff
{
    string DoThingOne<T>(T genericParm);
    string DoThingOne<T>(T genericParm, int anotherParm);
    string SendRequest<T>(IRequest<T> request);
}
interface IRequest<T>
{
    T GenericParm { get; set; }
    int IntParm { get; set; }
}
abstract class ThingDoerBase : IDoStuff
{
    // simplifed but default for the integer parm
    public virtual string DoThingOne<T>(T parm) => DoThingOne(parm, 25); 
    **// I want to make this virtual but because it has to new up a WebRequest defined in the other project it has to live there.**
    public abstract string DoThingOne<T>(T parm; int anotherParm);
    public abstract string SendRequest<T>(IRequest<T> request);
}

实施1项目

class Imp1Request<T> : IRequest<T>
{
    public T GenericParm {get;set;}
    public int IntParm {get;set;}
}
class ThingDoer : ThingDoerBase 
{
    public override string DoThingOne<T>(T parm, int anotherParm)
    {
        var req = new Imp1Request<T> { GenericParm = parm; IntParm = anotherParm };
        return SendRequest(req);
    }
    public override string SendRequest<T>(IRequest<T> req)
    {
        // implementation for this guy is not important.
    }
}

我想将抽象方法DoThingOne从抽象基类转换为调用抽象SendRequest的虚方法(类似于覆盖方法在实现中的作用)。

换句话说,我希望实现类中唯一的方法是SendRequest<T>(IRequest<T> req);,其余方法在基类中。

我考虑过在图书馆项目中创建RequestBase : IRequest;但是,为简洁起见,我在此省略的一件事是,IRequest的每个实现都需要不同的属性,我不想用它来污染库。例子是

Implement1

class Imp1Request<T> : IRequest<T>
{
    [JsonProperty("_GenericParm")]
    public T GenricParm {get;set;}
}

Implement2

class Imp2Request<T> : IRequest<T> 
{
    [XmlAttribute("StringParm")]
    public T GenricParm {get;set;}
}

我认为工厂的做法是针对某些事情的,我只是在努力解决如何使其适应我的情况。

还有另一种方法来构建它吗?或者实现尽可能多的样板代码在基类中的目标?

1 个答案:

答案 0 :(得分:1)

您可以将工厂注入 ThingDoerBase

您的IRequest接口:

interface IRequest { }

interface IRequest<T>:IRequest
{
    T GenericParm { get; set; }
    int IntParm { get; set; }
}

你的基类:

abstract class ThingDoerBase : IDoStuff
{
    private Func<IRequest> _factory;

    protected ThingDoerBase(Func<IRequest> factory) => _factory = factory;

    // simplifed but default for the integer parm
    public virtual string DoThingOne<T>(T parm) => DoThingOne(parm, 25); 
    public virtual string DoThingOne<T>(T parm, int anotherParm)
    {
        if(!(_factory() is IRequest<T> request))
            throw new InvalidOperationException();

        request.GenericParm = parm;
        request.IntParm = anotherParm;
        return SendRequest(request);
    }
    public abstract string SendRequest<T>(IRequest<T> request);

    public void ChangeRequestFactory(Func<IRequest> factory) => _factory = factory;
}

示例实施:

    class Foo :ThingDoerBase{
        public Foo(Func<IRequest> factory) : base(factory) { }
        public override string SendRequest<T>(IRequest<T> request) => 
            throw new NotImplementedException();
    }

并测试:

    var foo = new Foo(() => new Imp1Request<int>());
    foo.DoThingOne(1);
    foo.DoThingOne("lol"); //will throw InvalidOperationException

    foo.ChangeRequestFactory(() => new Imp1Request<string>());
    foo.DoThingOne(1);//will throw InvalidOperationException
    foo.DoThingOne("lol");