Home > database >  Is there a way for classes to communicate with one another without connecting them through object re
Is there a way for classes to communicate with one another without connecting them through object re

Time:09-28

The hardest problem I'm having is illustrating the problem. It runs, but it feels like there's a much cleaner way to achieve the same thing. Is there a way for a method in one class to communicate with another object, without having to create a reference to that object as a property in the class? For instance, here's a very simplified example. I'd like to create a shelter object that stores pets. As well, I have a class that wants to interact with the shelter, potentially adding a pet to the shelter's list of pets. Is this only achievable through referencing the shelter on the encounter object? This doesn't feel like it scales well when we need one object to interact with many others, or many objects to interact with this one.

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());
    }
}

Thoughts?

CodePudding user response:

Your code actually isn't valid as is-- you've got to create an instance of the Encounter class, which will typically look something like this:

encounter = new Encounter();

This is where you're supposed to initialize and create that encounter. And if an encounter isn't valid with a shelter, you have to provide it. In this case it is idiomatic to pass it as an argument to the constructor:

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

The constructor might look like this:

class Encounter
{
    protected readonly Shelter _shelter;

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

Now your encounter always knows what shelter it is associated with by accessing its own _shelter field.

To answer your question-- is there some way for your Shelter to automatically figure out what Encounter it goes with? The answer is no. This is because you can have more than one shelter.

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

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

You have to tell it which one:

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

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

CodePudding user response:

If you use delegates, you can achieve the results you want without having to add any class references in the Encounter class. Delegates provide you with the flexibility necessary to add pets to as many shelters as you wish, as well as any other kind of side effects. You can read more about them here 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);
        }
    }
}

  • Related