如何在部分类中“覆盖”一个方法?

4
我是一个有用的助手,可以为您翻译文本。
我一直在寻找解决我们公司一个复杂问题的方法。我们公司是一个由四个公司组成的联盟,覆盖了我们国家的四个“地区”。
我们分支机构开发了一个C# WebService,并将该项目分发给其他分支机构的开发人员。每个人都在自己的服务器上托管WebService。
现在,由于不同公司之间的关系不好,我必须调整现有的方法以适应我们的“区域需求”。
所以我有这个类:
public partial class MyClass{
     public static ComplexReturnType MyMethod(){
          // National code. Everyone uses this block of code.
     }
}

我创建了一个名为“Regional”的文件夹,将在向其他分支分发DLL时从编译中排除该文件夹。在该文件夹内,我创建了MyClass.cs文件,并按照以下方式继续操作:

public partial class MyClass{
     public static ComplexReturnType MyMethod(){
          // Regional code. Only my commpany will use this.
     }
}

方法MyMethod在其他文件中被调用。我了解partial的工作原理,但是我找不到一个适合我的需求而不需要创建子类并重写其他文件中已经存在的每个调用的解决方案。
有人有处理这个问题的想法吗? 回答后编辑 我决定采用策略设计模式,在完成后我想到“如果一个分支决定覆盖任何方法,则所有其他分支都必须使用其地区策略类中的国家代码覆盖相同的方法”。
所以这不是很好。相反,我做了这个:
public class VStrategy
{
    public virtual ComplexReturnType MyMethod(){
        // National code. Method moved from MyClass
    }
    public virtual AnotherReturnType MySecondMethod(){
        // National code. Method moved from MyClass
    }
}

public class SomeBranchStrategy: VStrategy
{
    public override ComplexReturnType MyMethod() {
        // Regional code for overriding a method
    }
}

public class AnotherBranchStrategy: VStrategy
{
    public override AnotherReturnType MySecondMethod(){ {
        // Regional code for overriding a method
    }
}

public class MyClass
{
    private static VStrategy _strategy = new VStrategy();
    public static VSTrategy Strategy { get {...}; set {...} }
    public static ComplexReturnType MyMethod()
    {
        return Strategy.MyMethod();
    }
    public static ComplexReturnType MySecondMethod()
    {
        return Strategy.MySecondMethod();
    }
}

这样,在没有界面的情况下,每个分支都可以覆盖任何它们想要覆盖的方法,而不会对其他分支造成影响。您只需将该方法代码移动到VStrategy类中,并在自己的区域类中进行覆盖。

希望本文对处于此种情形的任何人有所帮助。


2
作为结果应该选择哪种方法? - zerkms
1
看起来你正在通过使用部分类使问题变得更加复杂。在我看来,使用良好的对象组合/继承是正确的方法。 - Cristian Lupascu
你可以使用部分类方法,但我认为你对全球化和本地化的概念选择不太恰当。微软推荐使用卫星程序集。 - Rene Niediek
2
@Extra: 现在你已经第一手体验到为什么“静态”容易导致开发死胡同。如果该方法是“虚拟的”(和/或是接口的一部分),那么只需用更专业的类的实例替换调用它的实例即可(您不需要重写每个调用)。把这个教训带回家。 - Jon
除非您使用条件编译符号,否则无法完成此操作。您可以添加一个标记来表示您所在地区的名称,并将代码放入该标记中,在另一个标记中添加国家代码方法。 - Akanksha Gaur
显示剩余3条评论
4个回答

8

正如Maurice Stam所说,封装变化。乍一看,我会使用策略模式: http://www.oodesign.com/strategy-pattern.html

public interface IStrategy
{
    ComplexReturnType MyMethod();
}

public class NationalDefaultStrategy : IStrategy
{
    public ComplexReturnType MyMethod() { }
}

public class BostonStrategy: IStrategy
{
    public ComplexReturnType MyMethod() { }
}

public class MyClass
{
    private static IStrategy _strategy = new NationalDefaultStrategy();
    public static ISTrategy Strategy { get {...}; set {...} }
    public static ComplexReturnType MyMethod()
    {
        return _strategy.MyMethod();
    }
}

这样,您就可以在运行时轻松更改正在使用的策略。
MyClass.Strategy = new BostonStrategy();

如果您将其设置为实例方法而不是静态方法(我可能会这样做),并决定使用像Castle Windsor这样的IoC容器,甚至可以在配置文件中连接策略。 编辑 从逻辑上讲,每个分支都应该有自己的配置文件。使用此方法有两个优点:

2
您当前的方法存在一些问题。
  1. 静态方法不能是虚拟的。
  2. 应该封装变化的部分。这意味着公司特定的代码应该至少在一个单独的类中(最好是一个单独的程序集)。您需要为基础程序集提供您的公司特定代码。您可以使用策略模式结合IoC/依赖注入来实现。
  3. 将基础方法设置为虚拟方法同时包含代码的风险是,复用的代码将被重复。解决此问题的方法是创建一个密封的方法,其中包含通用代码,并使用公司内部将从密封的方法调用的抽象(或空虚拟)方法。结合我之前的观点,这意味着调用已在注入实例上实现的方法。
  4. 如果问题仅涉及本地化,则应使用.NET提供的解决方案(即包含特定文化资源的卫星程序集)。但是,您将同一个国家分为4个地区,因此我假设您具有区域特定的逻辑而不是本地化问题。
实现上述建议的示例代码:
public class SharedClass
{
    private readonly IRegionCode m_RegionLogic;

    // Constructor with dependency injection
    public SharedClass(IRegionCode mRegionLogic)
    {
        this.m_RegionLogic = mRegionLogic;
    }

    // Method called by the webservice
    public void YourMethod()
    {
        // reused base logic here
        Trace.Write("Somehting");

        // Invoke region specific code
        m_RegionLogic.Foo();

        // reused base logic here
        Trace.Write("Somehting");
    }
}

// Contract for regions to implement
public interface IRegionCode
{
    void Foo();
}

// Example of an injected class
public class FirstRegionCode : IRegionCode
{
    public void Foo()
    {
        Trace.Write("Bar");
    }
}

是的。基本上,这个问题应该通过组合和配置来解决,而不是通过部分或继承来解决。 - H H

1

我认为您误解了部分类的作用!创建部分类只是意味着将类的源代码拆分成单独的文件。与将所有源代码编写到同一文件中没有区别,因此基本上您编写的内容是:

public class MyClass{
     public static ComplexReturnType MyMethod(){
          // National code. Everyone uses this block of code.
     }

     public static ComplexReturnType MyMethod(){
          // Regional code. Only my commpany will use this.
     }
}

看到问题了吗?

1

你需要使用编译标签来避免 例如:

public partial class MyClass
    {
#if National
        public static void NationalMethod()
        {

        }
#endif

    }


    public partial class MyClass
    {
#if Regional
        public static void NationalMethod()
        {

        }
#endif
    }

在项目属性中,构建 -> 条件编译符号:根据需求的区域添加“Regional”或“National”。

编译标记很脆弱,而且在存在使用标准语言特性解决问题的现有模式时,并不是一个有用的方法。 - David Clarke

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