使用相同的 Class 并覆盖一种方法

Using the Same Class with One Method Being Overridden

我正在使用 class A 的实例。但是,我想用其他方法替换 class 中的一种方法。我知道我可以写一个不同的 class 并继承原来的 class 但我不应该触及声明实例的代码部分。

我已尝试创建 class B 并覆盖该特定方法,但显然这不会起作用,因为 class A 中的线程已在 Main() 中启动。这是代码示例。感谢您的帮助!!

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApplication2
{
    class Program
    {
        /* The Original Class A that I am Not Supposed to Touch */
        public class A
        {
            public A()
            {
                Thread thread_A = new Thread(Method1);
                thread_A.Start();
            }
            public void Method1()
            {
                while(true)
                {
                    Thread.Sleep(1000);
                    Method2();
                }

            }

            /* I Want To Replace This Method with Something Else */
            public virtual void Method2()
            {
                Console.WriteLine("This is in Class A");
            }

        }
        /* Some Random Class I Created Myself that I Do Not Know If It Works */
        public class B: A
        {
            /* The Method that I Want To Use */
            public override void Method2()
            {
                Console.WriteLine("This is in Class B");
            }
        }
        static void Main(string[] args)
        {
            /* I am not supposed to touch this either, it has to be an instance of A */
            A instanceA = new A();

            /* But I want the print result to be "This is in Class B" */
        }
    }
}

实际场景:Class A用于通过websocket持续发送消息。 Class A 中有一个包装消息的方法。现在我试图用不同的格式包装消息。所以我试图替换的方法是在 Class A 中执行的中间。 Class A 发送消息的线程已经在我无法触及的其他文件中启动...

更新:如果我必须在 A 中进行更改,是否有任何建议可以很好地覆盖这个项目的方法?由于 A 是不同项目共享的公共文件。

您描述的问题在您给定的限制条件下实际上无法解决。这不是一个告诉你如何做你想做的事情的答案,但如果答案是不可能的,那么,这就是答案。但我们仍然可以看看为什么这是不可能的,以及我们可以做些什么。

您的代码执行此操作:

A instanceA = new A();

如果不更改 A 的功能或将此代码更改为 使用 A,则无法更改此代码的行为。其中一个约束必须改变。

这说明了耦合,即当我们的代码的不同部分相互关联时,它们不能单独工作,并且我们不能在不更改其他部分的情况下更改一个部分。

这是一个示例,它没有使用 AB 这样的名称,因为这样会让人难以阅读。我并没有想太多 - 这只是一个例子来说明一个观点:

public class Stove
{
    public void CookFood() { }
}

public class Chef
{
    public void MakeFood()
    {
        var stove = new Stove();
        stove.CookFood();
    } 
}

public class Parent
{
    public void FeedChildren()
    {
        var stove = new Stove();
        stove.CookFood();
    }
}

如果没有 Stove,这些 class 中的任何一个都无法工作。从某种意义上说,您可以说 Stove 是其中的一部分。如果您更改 Stove,您实际上是在更改这两个 class。您也无法在不测试 Stove 的情况下测试其中任何一个 class。

更重要的是,因为这两个 class 都耦合到 Stove,它们也相互耦合 如果其中一个 classes 需要 Stove 做一些不同的事情,你必须改变 Stove。结果会影响到其他class。这意味着对 Chef 的更改会影响 Parent,反之亦然。

这是不可取的。它使我们的应用程序像一个大的 class 而不是可以独立更改的小块一样工作。

消除这种耦合的一种常见方法是依赖抽象而不是具体实现。我们可以将代码更改为如下所示:

public interface IStove
{
    void CookFood();
}

public class Chef
{
    private readonly IStove _stove;

    public Chef(IStove stove)
    {
        _stove = stove;
    }

    public void FeedChildren()
    {
        _stove.CookFood();
    } 
}

public class Parent
{
    private readonly IStove _stove;

    public Parent(IStove stove)
    {
        _stove = stove;
    }

    public void MakeFood()
    {
        _stove.CookFood();
    }
}

现在 class 都不依赖于具体的 class、Stove。两者都依赖于一个抽象——在本例中是一个接口——IStove.

如果我有一个Stoveclass并且它同时满足ChefParent的需要,两者都可以使用它。但是,如果我需要一个不同的 Stove,比如 GrillGiantPizzaOven 怎么办?现在我可以创建一个不同的 class 来实现 IStove。我不必更改现有的 classes.

现在没有 class 耦合到 IStove 的实现,并且它们彼此不耦合。我们可以独立更改 ChefParentStove,而无需强制更改其他 class。


通过构造函数传递 IStove 等依赖项而不是让 classes 创建它们 (new Stove()) 的模式是依赖项注入。这是一个有用的模式,我强烈建议您阅读并尝试一下。最终你可能会依赖它(没有双关语意)但这超出了这个答案的范围。


更多细节 - 您可能已经注意到此答案中没有 class 继承。并不是说继承不好,而是可以这样。这是引入耦合的另一种方式。 IStove 的一个实现从另一个实现继承可能是有意义的,但它很可能会引入其他问题。

我的建议是提防此类问题的解决方案开始继承。寻找不涉及继承的解决方案,只有当它开始变得明显有意义时才使用它,如果你创建了继承,不要犹豫,一旦它变得混乱就撤消它并寻找其他解决方案。


还有一个细节:依赖像 IStove 这样的接口可以减少问题,但是随着我们的代码变得越来越复杂,即使对于不同的 class 依赖相同的抽象也会在某种程度上耦合它们一起。 Interface Segregation Principle 解决了该问题。这只是雷达上的东西。