首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >抽象方法的具体实现

抽象方法的具体实现
EN

Stack Overflow用户
提问于 2016-12-22 23:59:19
回答 2查看 418关注 0票数 1

我的目标是向客户端隐藏我正在构建的类的所有细节,包括要实例化的具体类。

客户端将枚举传递给一个工厂,该工厂返回相应派生类的实例,如下所示:

代码语言:javascript
复制
IAutomobile auto = Autofactory.GetAuto(param);

我创建了一个基类来完成大部分工作,但我需要特定的派生类来实现特定的逻辑。

代码语言:javascript
复制
public interface IAutomobile
{
    void Rename(string p1, int p2);
}
public abstract class Automobile : IAutomobile
{
    // Lots of properties and methods...

    public abstract void Rename(string p1, int p2);
}

public class Jeep : Automobile
{
    public override void Rename(string p1, int p2)
    {
        // Uses p1 & p2 with the base class
    }
}

现在,客户端可以调用:

代码语言:javascript
复制
auto.Rename("s1", "s2");

当然,在我创建另一个派生类以不同的签名实现"Rename()“方法之前,一切都很好。

代码语言:javascript
复制
public class Audi : Automobile
{
    public override void Rename(int i, SomeOtherClass someOtherClass)
    {
        //Does something with params
    }
}

第二个实现有一个不同的签名,这并不令人意外地抛出编译错误。

因此,通过使用这样的字典,我试图使传递的参数更加“灵活”:

代码语言:javascript
复制
public interface IAutomobile
{
    void Rename(Dictionary<object, object> parameters);
}

客户端:

代码语言:javascript
复制
public class client
{
    public void Client()
    {
        var parameters = new Dictionary<object, object>();
        IAutomobile auto = AutoFactory.GetFactory();

        parameters.Add("Param1Name", "string1");
        parameters.Add("Param2Name", 21);
        auto.Rename(parameters);
    }
}

派生类:

代码语言:javascript
复制
public class Audi : Automobile, IAutomobile
{
    public override void Rename(Dictionary<object, object> parameters)
    {
        //  cast/box/unbox from dictionary objects...
        //  does something unique for Audis...
    }
} 

所以,我就是这样用字典实现的,其中参数是键/值对,但这似乎是糟糕的。我不明白它怎么会给我买任何东西。

或者,我可以创建一个对象,它表示所有派生类参数的联合,但同样,这看起来很糟糕。

有人能建议我如何安排这件事,这样就不需要演员、拳击和非拳击了?

我不介意公开与Rename()方法一起使用的对象,例如:

代码语言:javascript
复制
auto.Rename(AudiFeatures);

代码语言:javascript
复制
auto.Rename(JeepFeatures);

(顺便说一句,我真的不想传递单个的对角线,我想传递对象)

这样的客户端调用将无法工作,因为我必须对客户端代码中的类型进行硬编码。我想在工厂中对其进行硬编码,但是如何返回正确的接口类型,以及工厂的返回类型是什么?

我不想这么做:

代码语言:javascript
复制
IAutomobile<JeepRenamingData> auto = Autofactory.GetAuto<JeepRenamingData>(param);

我想这么做:

代码语言:javascript
复制
IAutomobile auto = Autofactory.GetAuto(param);
auto.Rename(myJeepRenamingData);

并让工厂返回正确的类型:

代码语言:javascript
复制
    public static IAuto GetAutomobileManager(AutoMaker manufacturer)
    {
        switch (manufacturer)
        {
            case AutoMaker.Jeep
                return new Jeep<JeepNamingOptions>();

            case AutoMaker.Audi
                return new Audi<AudiNamingOptions>();
        }

    }
EN

回答 2

Stack Overflow用户

发布于 2016-12-23 00:06:58

最直接的想法是使用泛型。你能做到吗?

代码语言:javascript
复制
public interface IAutomobile { }

public interface IAutomobile<P1, P2> : IAutomobile
{
    void Rename(P1 p1, P2 p2);
}

public abstract class Automobile<P1, P2> : IAutomobile<P1, P2>
{
    // Lots of properties and methods...

    public abstract void Rename(P1 p1, P2 p2);
}

public class Jeep : Automobile<string, int>
{
    public override void Rename(string p1, int p2)
    {
        // Uses p1 & p2 with the base class
    }
}

然后,客户端调用将如下所示:

代码语言:javascript
复制
IAutomobile<string, int> auto = Autofactory.GetAuto<string, int>(param);
auto.Rename("Foo", 42);
IAutomobile auto_plain = auto;

根据你的最新情况,这是我现在的建议:

代码语言:javascript
复制
IAutomobile<JeepFeatures> auto = Autofactory.GetAuto<JeepFeatures>(param);
auto.Rename(new JeepFeatures());
IAutomobile auto_plain = auto;


public interface IAutomobile { }

public interface IAutomobile<P> : IAutomobile
{
    void Rename(P parameters);
}

public abstract class Automobile<P> : IAutomobile<P>
{
    public abstract void Rename(P parameters);
}

public class Jeep : Automobile<JeepFeatures>
{
    public override void Rename(JeepFeatures parameters)
    {
    }
}
票数 1
EN

Stack Overflow用户

发布于 2016-12-23 10:52:01

对我来说,无论哪种方式,您当前的方法都存在设计缺陷。

虽然你想要完全隐藏混凝土汽车的细节,你需要具体的细节,因为你不能工作的汽车,你根本不知道.总之,--我看到了过多的抽象

不需要像IAutomobile这样过于抽象的接口来操纵您的汽车,您应该使用接口的强大功能从头开始解决您的问题:

代码语言:javascript
复制
public interface ICanRename<TArgs>
    where TArgs : class
{
    void Rename(TArgs args);
}

public interface IAutomobile 
{
    // Other common behaviors 
}

public interface IJeep : IAutomobile, ICanRename<JeepRenameArgs>
{
}

public class JeepRenameArgs {}

public class Jeep: IJeep
{
    public void Rename(JeepRenameArgs args)
    {
        // Rename stuff 
    }
}

public class AutomobileFactory
{
    private Dictionary<Type, Type> AutomobileImplementations = new Dictionary<Type, Type>
    {
        { typeof(IJeep), typeof(Jeep) } 
    };

    public TAutomobile Create<TAutomobile>() 
        where TAutomobile : IAutomobile
    {
        TAutomobile automobile = (TAutomobile)Activator.CreateInstance(AutomobileImplementations[typeof(TAutomobile)]);

        // Some initialization stuff here

        return automobile;
    }
}

因此,您可以获得如下的汽车实现:

代码语言:javascript
复制
    AutomobileFactory automobileFactory = new AutomobileFactory();
    IJeep jeep = automobileFactory.Create<IJeep>();

    jeep.Rename(new JeepRenameArgs());

    // or even:
    ICanRename<JeepRenameArgs> jeep2 = automobileFactory.Create<IJeep>() as ICanRename<JeepRenameArgs>;
    jeep2.Rename(new JeepRenameArgs());

看看如何在不知道实现或接口的情况下重命名一个Jeep

不管怎样..。

看来你最终会重新发明方向盘。上面的代码,甚至是您的代码,似乎是控制容器服务定位器的基本反转。

使用像http://www.castleproject.org/这样的东西怎么样?

代码语言:javascript
复制
WindsorContainer container = new WindsorContainer();
container.Register
(
      Classes.FromThisAssembly().BasedOn<IAutomobile>()
                   .WithServiceAllInterfaces().LifestyleTransient()
);

IJeep jeep = container.Resolve<IJeep>();

或者,为了不走向邪恶(你应该避免服务定位器反模式),你应该利用依赖注入

代码语言:javascript
复制
public class YourClass
{
      public YourClass(IJeep jeep)
      {
          Jeep = jeep;
      }

      private IJeep Jeep { get; }

      public void DoStuff()
      {
           Jeep.Rename(new JeepArgs());
      }
}

...and让反转控制容器为您注入所需的汽车实现!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41293399

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档