Powiązania dwukierunkowe

0

Witam,
Zacząłem swój mały projekcik, poruszam się jak dziecko we mgle i ciągle potykam o sznurowadła :) W moim ostatnim poście Shalom napisał, że nie ma nic złego w powiązaniach dwukierunkowych pomiędzy klasami. Nie wiem tylko jak rozwiązuje się praktyczny problem - automatycznego wiązania obiektów. Mam klasę klasa_szkolna i klasę dziecko. Kiedy przypisuję dziecko do klasy, chciałbym od razu, by w obiekcie klasa pojawiło się dziecko a w obiekcie dziecko pojawiła się informacja, do jakiej klasy należy. Tylko czy w ogóle warto to automatyzować? Moje rozwiązanie:

 class Dziecko : Osoba
{
        public bool PrzypiszDoKlasy(Klasa_szkolna klasa)
        {
            if (this.klasa_szkolna == klasa)
            {
                // nie przypisano (juz byla przypisana)
                return false;
            }
            else
            {
                this.klasa_szkolna = klasa;
                klasa.DodajUcznia(this);
                return true;
            }
        }
}
class Klasa_szkolna
 {
        public bool DodajUcznia(Dziecko uczen)
        {
            if (uczniowie.Contains(uczen))
            {
                return false; 
            }
            else
            {
                uczen.PrzypiszDoKlasy(this);
                uczniowie.Add(uczen);
                return true;
            }
        }
}

Zdaje się, że działa prawidłowo. Zastanawiam się tyko, czy jest może jakieś inne, prostsze, mniej zamotane rozwiązanie? Może lepiej darować sobie automatyzacje wzajemnego powiązania i pamiętać, by za każdym razem wykonywać obie operacje dwoma osobnymi instrukcjami?

1

Możesz zrobić coś takiego:

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

namespace App
{
    class Student
    {
        public Classroom Classroom { get; private set; }
        public string Name { get; private set; }

        public Student(string name, Classroom classroom)
        {
            this.Name = name;
            this.Classroom = classroom;
        }

        public override bool Equals(object obj)
        {
            return (obj as Student).Name == this.Name;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    class Classroom
    {
        public IList<Student> Students { get; private set; }
        public string Name { get; private set; }

        public Classroom(string name)
        {
            this.Name = name;
            this.Students = new List<Student>();
        }

        public void AddStudent(Student student)
        {
            if (!this.Students.Contains(student))
            {
                this.Students.Add(student);
            }
        }
    }

    class School
    {
        private IList<Classroom> classrooms;

        public School(params Classroom[] classrooms)
        {
            this.classrooms = new List<Classroom>();
            foreach (var c in classrooms)
            {
                this.classrooms.Add(c);
            }
        }

        public void AddStudent(Student student)
        {
            var classroom = this.classrooms.SingleOrDefault(c => c == student.Classroom && !c.Students.Contains(student));
            if (classroom != null)
            {
                classroom.AddStudent(student);
            }
        }

        public void ShowAllStudents()
        {
            foreach (var c in this.classrooms)
            {
                Console.WriteLine(c.Name);
                foreach (var s in c.Students)
                {
                    Console.WriteLine(s.Name);
                }
                Console.WriteLine();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var firstClass = new Classroom("1A");
            var secondClass = new Classroom("2B");

            var school = new School(firstClass, secondClass);

            school.AddStudent(new Student("Maciek", firstClass));
            school.AddStudent(new Student("Maciek", firstClass));
            school.AddStudent(new Student("Janek", firstClass));
            school.AddStudent(new Student("Czesiek", firstClass));

            school.AddStudent(new Student("Krzysiek", secondClass));
            school.AddStudent(new Student("Shalom", secondClass));
            school.AddStudent(new Student("Shalom", secondClass));
            school.AddStudent(new Student("Pietrek", secondClass));

            school.ShowAllStudents();
        }
    }
}

Jak sobie popatrzysz na to np. przez debuger to zobaczysz, że każdy student posiada swoją klasę oraz każda klasa posiada swoich studentów. Kiedy szkoła dodaje ucznia realizowane jest właśnie to "dwukierunkowe połączenie":

  • Przy tworzeniu studenta wymuszamy by skojarzono go ze swoją klasą;
  • Przy dodawaniu studenta do szkoły wymuszamy by wrzucić go do takiej klasy z jaką został skojarzony w punkcie wyżej.
0

Dzięki za kawał ciekawego kodu do analizy. Oczywiście wyłożyłem się na

var classroom = this.classrooms.SingleOrDefault(c => c == student.Classroom && !c.Students.Contains(student));

Że niby z Tej szkoły (this) z dostępnych klas (clasrooms) weź jakąś (jedną, lub zwróć null jak nie ma) że klasa jest taka, jaką ma przypisaną już uczeń (==) ale żeby go nie było już czasem na liście klasy (&& !...)?

A wracając do mojego pytania, chodziło mi raczej o mechanizm, który gwarantowałby, że niezależnie od tego, czy uruchomię metodę ucznia, polegającej na dodaniu go do klasy, czy też metodę obiektu klasy, polegającą na wpisaniu ucznia na listę, powiązanie dwustronne zostanie utworzone. W Twoim kodzie w klasie Student w ogóle nie ma metody przypisującej gościa do klasy. Dochodzę jednak do wniosku, że mechanizm o którym myślałem w ogóle nie jest potrzebny :) Niemniej dzięki za ciekawy kod i zagwozdkę z lambdą.

1

Lambda mówi dokładnie to: Iteruj klasy w szkole w poszukiwaniu takiej, która jest równa klasie przypisanej do studenta i jednocześnie tego studenta nie zawiera. Jeżeli klasa zostanie znaleziona to wynik wyrażenia będzie różny od null i zostanie do takiej klasy przypisany student.

W Twoim kodzie w klasie Student w ogóle nie ma metody przypisującej gościa do klasy. - ależ jest. Tą metodą jest konstruktor klasy Student.

1 użytkowników online, w tym zalogowanych: 0, gości: 1