使用相同的 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
,则无法更改此代码的行为。其中一个约束必须改变。
这说明了耦合,即当我们的代码的不同部分相互关联时,它们不能单独工作,并且我们不能在不更改其他部分的情况下更改一个部分。
这是一个示例,它没有使用 A
和 B
这样的名称,因为这样会让人难以阅读。我并没有想太多 - 这只是一个例子来说明一个观点:
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
.
如果我有一个Stove
class并且它同时满足Chef
和Parent
的需要,两者都可以使用它。但是,如果我需要一个不同的 Stove
,比如 Grill
或 GiantPizzaOven
怎么办?现在我可以创建一个不同的 class 来实现 IStove
。我不必更改现有的 classes.
现在没有 class 耦合到 IStove
的实现,并且它们彼此不耦合。我们可以独立更改 Chef
、Parent
或 Stove
,而无需强制更改其他 class。
通过构造函数传递 IStove
等依赖项而不是让 classes 创建它们 (new Stove()
) 的模式是依赖项注入。这是一个有用的模式,我强烈建议您阅读并尝试一下。最终你可能会依赖它(没有双关语意)但这超出了这个答案的范围。
更多细节 - 您可能已经注意到此答案中没有 class 继承。并不是说继承不好,而是可以这样。这是引入耦合的另一种方式。 IStove
的一个实现从另一个实现继承可能是有意义的,但它很可能会引入其他问题。
我的建议是提防此类问题的解决方案开始继承。寻找不涉及继承的解决方案,只有当它开始变得明显有意义时才使用它,如果你创建了继承,不要犹豫,一旦它变得混乱就撤消它并寻找其他解决方案。
还有一个细节:依赖像 IStove
这样的接口可以减少问题,但是随着我们的代码变得越来越复杂,即使对于不同的 class 依赖相同的抽象也会在某种程度上耦合它们一起。 Interface Segregation Principle 解决了该问题。这只是雷达上的东西。
我正在使用 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
,则无法更改此代码的行为。其中一个约束必须改变。
这说明了耦合,即当我们的代码的不同部分相互关联时,它们不能单独工作,并且我们不能在不更改其他部分的情况下更改一个部分。
这是一个示例,它没有使用 A
和 B
这样的名称,因为这样会让人难以阅读。我并没有想太多 - 这只是一个例子来说明一个观点:
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
.
如果我有一个Stove
class并且它同时满足Chef
和Parent
的需要,两者都可以使用它。但是,如果我需要一个不同的 Stove
,比如 Grill
或 GiantPizzaOven
怎么办?现在我可以创建一个不同的 class 来实现 IStove
。我不必更改现有的 classes.
现在没有 class 耦合到 IStove
的实现,并且它们彼此不耦合。我们可以独立更改 Chef
、Parent
或 Stove
,而无需强制更改其他 class。
通过构造函数传递 IStove
等依赖项而不是让 classes 创建它们 (new Stove()
) 的模式是依赖项注入。这是一个有用的模式,我强烈建议您阅读并尝试一下。最终你可能会依赖它(没有双关语意)但这超出了这个答案的范围。
更多细节 - 您可能已经注意到此答案中没有 class 继承。并不是说继承不好,而是可以这样。这是引入耦合的另一种方式。 IStove
的一个实现从另一个实现继承可能是有意义的,但它很可能会引入其他问题。
我的建议是提防此类问题的解决方案开始继承。寻找不涉及继承的解决方案,只有当它开始变得明显有意义时才使用它,如果你创建了继承,不要犹豫,一旦它变得混乱就撤消它并寻找其他解决方案。
还有一个细节:依赖像 IStove
这样的接口可以减少问题,但是随着我们的代码变得越来越复杂,即使对于不同的 class 依赖相同的抽象也会在某种程度上耦合它们一起。 Interface Segregation Principle 解决了该问题。这只是雷达上的东西。