类 有没有一种方法可以在不通过对象引用连接它们的情况下相互通信?

Is there a way for classes to communicate with one another without connecting them through object references?

我遇到的最困难的问题是说明问题。它可以运行,但感觉有一种更简洁的方法来实现同样的事情。有没有一种方法可以让一个 class 中的方法与另一个对象通信,而不必在 class 中创建对该对象的引用作为 属性?例如,这是一个非常简化的示例。我想创建一个存放宠物的庇护所对象。此外,我有一个 class 想要与收容所互动,可能会将宠物添加到收容所的宠物列表中。这只能通过引用遭遇对象上的避难所来实现吗?当我们需要一个对象与许多其他对象交互,或者许多对象与这个对象交互时,这感觉不太好扩展。

using System;
using System.Collections.Generic;

class Program
{
    static Shelter shelter;
    static Encounter encounter;
    static void Main(string[] args)
    {
        // this is what I'd like to avoid
        encounter = new Encounter();
        encounter.shelter = shelter;
    }
}

class Pet
{
    string name;
    public Pet()
    {
        name = "DefaultDog";
    }
}

class Shelter
{
    public List<Pet> pets;
    public void AddPet(Pet pet)
    {
        pets.Add(pet);
    }
}

class Encounter
{
    // this is what I'd like to avoid
    public Shelter shelter;
    public void CapturePet()
    {

        shelter.AddPet(new Pet());
    }
}

想法?

你的代码实际上是无效的——你必须创建一个 Encounter class 的实例,它通常看起来像这样:

encounter = new Encounter();

这是你应该初始化和创建那个遭遇的地方。如果遭遇对避难所无效,则您必须提供避难所。在这种情况下,将它作为参数传递给构造函数是惯用的:

shelter = new Shelter();
encounter = new Encounter(shelter);

构造函数可能如下所示:

class Encounter
{
    protected readonly Shelter _shelter;

    public Encounter(Shelter shelter)
    {
        _shelter = shelter;
    }
}

现在你的遭遇总是通过访问它自己的 _shelter 字段知道它与哪个避难所相关联。

回答您的问题 -- 是否有某种方法可以让您的 Shelter 自动找出 Encounter 的含义?答案是不。这是因为你可以拥有不止一处庇护所。

var shelters = new List<Shelter>();    
shelters.Add(new Shelter());
shelters.Add(new Shelter());

var encounter = new Encounter();  //Which shelter is this associated with?

你必须告诉它是哪一个:

var shelters = new List<Shelter>();    
shelters.Add(new Shelter());
shelters.Add(new Shelter());

var encounter = new Encounter(shelters[0]); 

如果您使用委托,则无需在 Encounter class 中添加任何 class 引用即可实现您想要的结果。代表为您提供了必要的灵活性,可以根据需要将宠物添加到尽可能多的庇护所,以及任何其他类型的副作用。你可以在这里阅读更多关于它们的信息 https://docs.microsoft.com/en-us/dotnet/standard/events/

using System;
using System.Collections.Generic;

namespace SODelegate
{
    class Program
    {
        static Shelter shelter = new();
        static Shelter anotherShelter = new();
        static Encounter encounter = new();


        static void Main(string[] args)
        {
            encounter.OnCapturePet += delegate (object sender, EventArgs eventArgs)
            {
                Console.WriteLine("Running first delegate");
                shelter.AddPet(new Pet());
            };
            encounter.OnCapturePet += delegate (object sender, EventArgs eventArgs)
            {
                Console.WriteLine("Running second delegate");
                anotherShelter.AddPet(new Pet());
            };

            encounter.CapturePet();
        }
    }


    class Pet
    {
        string name;
        public Pet()
        {
            name = "DefaultDog";
        }
    }

    class Shelter
    {
        public List<Pet> pets = new();
        public void AddPet(Pet pet)
        {
            pets.Add(pet);
        }
    }

    class Encounter
    {
        public event EventHandler OnCapturePet;

        public void CapturePet()
        {
            Console.WriteLine("Running capture pet");
            this.OnCapturePet(this, EventArgs.Empty);
        }
    }
}