代码之家  ›  专栏  ›  技术社区  ›  Nate CSS Guy

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

  •  1
  • Nate CSS Guy  · 技术社区  · 6 年前

    假设我有以下几点:

    图书馆项目 :

    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的每个实现都需要不同的属性,而我不希望这些属性污染图书馆。例如

    实施1

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

    实施2

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

    我认为工厂的方法是对一些东西,我只是在努力适应我的情况。

    有没有其他方法来构造这个?或者实现尽可能多地在基类中使用样板代码的目标?

    1 回复  |  直到 6 年前
        1
  •  1
  •   taquion    6 年前

    你可以把工厂注入你的 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");