metody virtualne-w każdej podklasie?

0

Mam trzy klasy:

class osoba
{
  // atrybuty

  virtual public void pracuj ()
{
  //kod
}
}

class dyrektor
{
  //atrybuty

  override public pracuj()
{
 //kod
}
}

class pracownik
{
//atrybuty

  override public pracuj()
  
   public void zamiataj()
{
// kod
}
}

Tworzę sobie listę zdefiniowaną typem Osoba, List<Osoba> osoba = new List<Osoba>();

dodaj osoby itd, pytanie jak mam wypisać w pętli np foreach metode pracownika zamiataj ? Teoretycznie można w klasie osoba zdefiniować tę metodę jako virtualną a w klasie pracownik nadpisać ,ale to nie tak powinno chyba działać? Przecież klasa z któej się dziedziczy nie powinna zawierać wszystkich możliwych metod każdej podklasy?

3

Jeśli chcesz zamiatać, to wybierz tylko obiekty klasy Pracownik.

0

No ale jak? skoro wszystko jest w liście przechowywane i to z niej wypisuje dane?

foreach(var i in mojalista)
{
  consoleWriteLine( mojalista.zamiataj) // nie można bo nie jest virtualna
}
2

Musisz mieć oddzielną listę Pracowników, albo z listy Osób wybrać tylko Pracowników.

Skoro jedna Osoba nie może zamiatać, to nie oczekuj, żeby kolekcja Osób mogła zamiatać.

1

Tak jak @somekind napisał możesz wybrać z listy Osób tylko Pracowników:

 
         //foreach (Pracownik osoba in osoby.Where(osoba => osoba is Pracownik)) // LUB
         foreach (var osoba in osoby.Where(osoba => osoba is Pracownik).Cast<Pracownik>())
         {
            osoba.Zamiataj();
         }
         //LUB
         foreach (var osoba in osoby)
         {
            var pracownik = osoba as Pracownik;
            if (pracownik != null)
            {
               pracownik.Zamiataj();
            }
            else
            {
               osoba.Pracuj();
            }
         }
1

visitor pattern (przykład w java)

package com.tmp;


import java.util.ArrayList;
import java.util.List;



interface Osoba {
    void pracuj();

    void accept(Visitor visitor);
}

class Dyrektor implements Osoba {
    @Override
    public void pracuj() {

    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class Pracownik implements Osoba {
    @Override
    public void pracuj() {

    }

    public void zamiataj() {
        System.out.println("Pracownik zamiata");
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

interface Visitor {
    public void visit(Dyrektor dyrektor);
    public void visit(Pracownik pracownik);
}

class PracownikZamiataVisitor implements Visitor {

    @Override
    public void visit(Dyrektor dyrektor) {
        System.out.println("ignoruje dyrektora");
    }

    @Override
    public void visit(Pracownik pracownik) {
        pracownik.zamiataj();
    }
}


class ZliczajVisitor implements Visitor {

    private int dyrektorCount = 0;
    private int pracownikCount = 0;

    @Override
    public void visit(Dyrektor dyrektor) {
        dyrektorCount++;
    }

    @Override
    public void visit(Pracownik pracownik) {
        pracownikCount++;
    }

    public int getDyrektorCount() {
        return dyrektorCount;
    }

    public int getPracownikCount() {
        return pracownikCount;
    }
}


public class Main {
    public static final void main(String[] arg) {
        List<Osoba> osoby = new ArrayList<Osoba>();
        osoby.add(new Dyrektor());
        osoby.add(new Pracownik());
        osoby.add(new Dyrektor());
        osoby.add(new Dyrektor());
        osoby.add(new Pracownik());

        Visitor visitor = new PracownikZamiataVisitor();
        for(Osoba osoba : osoby) {
            osoba.accept(visitor);
        }

        ZliczajVisitor zliczajVisitor = new ZliczajVisitor();
        for(Osoba osoba : osoby) {
            osoba.accept(zliczajVisitor);
        }

        System.out.println("dyrektorow : " + zliczajVisitor.getDyrektorCount() + "\n" + "pracownikow : " + zliczajVisitor.getPracownikCount());
    }
}


0

Mnie zastanawia dlaczego pracownik ma mieć jakąś szczególną metodę do wykonywania pracy.
Jak będziesz miał dyrektora to będziesz miał metodę zarządzaj, a jak kierowcę to kieruj? Powinieneś raczej umieć rozróżniać pracowników po tym co potrafią zrobić i wybranemu pracownikowi zlecić "zrób to co potrafisz".
Chodzi mi o to, że nie szukasz pracownika który umie zamiatać, tylko szukasz sprzątacza, bo on jest od zamiatania.
Bez zabezpieczeń ale ideę chyba uchwyciłem.

 
public interface IEmployee
        {
            void DoWork();
        }

        public interface ICleaner: IEmployee
        {
            //jakieś specyficzne cechy sprzątacza            
        }

        /// <summary>
        /// Kierownik jakiejś konkretnej grupy pracowników
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public interface IManager<T> : IEmployee
        {
            List<T> Subordinates { get; set; }
        }

        public interface IManager : IManager<IEmployee>
        {
            //jakieś specyficzne cechy kierownika                        
        }

        public interface ICleanersManager : IManager<ICleaner> 
        {         
            //jakieś ciekawe cechy kierownika sprzataczy
        }

        public class Cleaner : ICleaner
        {
            public void DoWork()
            {
                Console.WriteLine("I'm happy cleaner.");
            }
        }

        public class Manager : IManager
        {
            public void DoWork()
            {
                Console.WriteLine("I'm happy manager.");
            }

            public List<IEmployee> Subordinates { get; set; }
        }
        
        public class CleanersManager :ICleanersManager
        {
            public List<ICleaner> Subordinates { get; set; }

            public void DoWork()
            {
                Console.WriteLine("Hej selected cleaner DoWork");
                //pierwszy z brzegu. Zakaładam, że mam podwładnego
                Subordinates[0].DoWork();
            }
        }

        static void Main(string[] args)
        {
            List<IEmployee> employees = new List<IEmployee>();

            var cleaner = new Cleaner();

            employees.Add(new Manager());
            employees.Add(cleaner);
            employees.Add(new Manager());
            //kierownik sprzataczy
            employees.Add(new CleanersManager()
            {
                Subordinates = new List<ICleaner>(new ICleaner[] { cleaner })
            });

            //wybieram sprzątacza i do roboty
            IEmployee selectedCleaner = employees.Where(k => k is ICleaner).FirstOrDefault();
            if (selectedCleaner != null)
            {
                //czyli twoje zamiataj
                selectedCleaner.DoWork();
            }

            //a można przez kierownika
            var cleanersManager = employees.Where(k => k is ICleanersManager).FirstOrDefault();
            if (cleanersManager != null)
            {
                cleanersManager.DoWork();
            }
        }
2

@Pabloss dlaczego metoda Zamiataj nie może być wywoływana w metodzie Pracuj klasy pracownik? Czy to jest inna forma aktywności? Kara?

2

cytując klasyka:

Demonical monk napisał(a)

Na (bardzo) chłopski rozum: Masz klasę Czlowiek, z niej dziedziczy Kobieta i Mezczyzna. Właśnie zrobiłeś coś analogicznego do wrzucenia pola z rozmiarem fujarki do mężczyzny, a metody ruchaj() do czlowieka. I próbujesz dymać czymś, co potencjalnie może być kobietą...

jeśli trzymasz listę osób to znaczy że wpadłeś w nich na pewną abstrakcję
skoro teraz nagle potrzebujesz tylko osób które mogą zamiatać to musisz wybrać osoby które są pracownikami

foreach(var pracownik in lista.OfType<Pracownik>())
    pracownik.zamiataj();

ale to nie jest ładny kod choć często spotykany; w kręgu na przykład programistów c++ byś został zlinczowany za wydobywanie z listy typu nadrzędnego konkretnego typu podrzędnego - to łamanie zasady podstawienia liskov

Jeżeli chcesz mieć tylko pracowników to trzymaj tylko pracowników. Skoro trzymasz listę osób to masz prawo tylko wywoływać metody wspólne dla wszelkiego rodzaju osób (abstrakcja).

Równie dobrze mógłbyś mieć przecież listę typu object i trzymać tam jednocześnie serwisy, drzewa, ludzi i godziny wypicia kawy, ale po co i gdzie tu porządek?

0
muf napisał(a):

w kręgu na przykład programistów c++ byś został zlinczowany za wydobywanie z listy typu nadrzędnego konkretnego typu podrzędnego - to łamanie zasady podstawienia liskov

No, ale to tylko w kręgu programistów C++, normalni programiści nie widzą Liskov tam, gdzie jej nie ma.

0
somekind napisał(a):

normalni programiści nie widzą Liskov tam, gdzie jej nie ma.

Liskov:
"Funkcje które używają wskaźników lub referencji do klas bazowych, muszą być w stanie używać również obiektów klas dziedziczących po klasach bazowych, bez dokładnej znajomości tych obiektów."

Jeżeli do funkcji f przekazujemy listę elementów typu A, to funkcja ta powinna działać bez wiedzy że z klasy A dziedziczą obiekty typu B i nie powinna traktować tych elementów w sposób szczególny
W przeciwnym wypadku gdy dodamy kolejne dziedziczenie z klasy A to najprawdopodobniej będziemy musieli modyfikować funkcję f a tutaj doszukiwałbym się pogwałcenia kolejnej literki z zestawu S,O,L,I,D

Masz inne zdanie?

BTW

tylko w kręgu programistów C++, normalni programiści (...)

wydaje mi się że implikujesz że normalny programista != programista C++
programiści C++ mają programistów C# za dzieci nieznające podstaw programowania
mniej więcej tak samo jak programiści C# myślą o programistach PHP

0
muf napisał(a):

Jeżeli do funkcji f przekazujemy listę elementów typu A, to funkcja ta powinna działać bez wiedzy że z klasy A dziedziczą obiekty typu B i nie powinna traktować tych elementów w sposób szczególny

To teraz wyjaśnij jak się to ma do tego kawałka kodu, w którym z listy obiektów klasy A wybierane są obiekty klasy dziedziczącej B, a następnie uruchamiana na nich metodę z tej klasy klasy?

wydaje mi się że implikujesz że normalny programista != programista C++

To nie moja implikacja tylko fakt. Sprawdź w słowniku, jeśli nie wierzysz.

programiści C++ mają programistów C# za dzieci nieznające podstaw programowania

Jak na razie na Twoim przykładzie widzimy doskonale, jak dobrze niektórzy programiści C++ znają podstawy programowania. [rotfl]

0
somekind napisał(a):

To teraz wyjaśnij jak się to ma do tego kawałka kodu, w którym z listy obiektów klasy A wybierane są obiekty klasy dziedziczącej B, a następnie uruchamiana na nich metodę z tej klasy klasy?

serio?

To nie moja implikacja tylko fakt. Sprawdź w słowniku, jeśli nie wierzysz.

mam sprawdzić w słowniku czy programiści c++ są normalni? :|

Jak na razie na Twoim przykładzie widzimy doskonale, jak dobrze niektórzy programiści C++ znają podstawy programowania. [rotfl]

nie jestem programistą C++
ani C#
ani nawet PHP

jak na razie mam wrażenie jakbym gadał z kimś kto się urwał z zakładu w lublińcu :|

0
muf napisał(a):

serio?

Na razie wygląda to tak, że komentujesz kod, którego nie rozumiesz i doszukujesz się w nim łamania zasad, których on nie łamie, więc ich chyba też nie rozumiesz.

mam sprawdzić w słowniku czy programiści c++ są normalni? :|

Nie, ale możesz tam sprawdzić słowa, których się czepiasz albo nie rozumiesz.

nie jestem programistą C++
ani C#
ani nawet PHP

Mam nadzieję, że nie jesteś nim w ogóle.

jak na razie mam wrażenie jakbym gadał z kimś kto się urwał z zakładu w lublińcu :|

To może przestań się do siebie odzywać?

2
somekind napisał(a):

Mam nadzieję, że nie jesteś nim w ogóle.

no widzisz nie zawsze na odpowiednim stanowisku są odpowiednie osoby
jak na przykład moderatorzy na forum

powinieneś dawno usunąć stąd posty niezwiązane z tematem a zamiast tego kontynuujesz flame
w Twoim ostatnim poście nie ma ani grama treści merytorycznej tylko zwykłe pyskówki :|

somekind napisał(a):

Czyli np. każdy komponent Windows Forms powinien w oddzielnej kolekcji trzymać swoje podkontrolki?

a gdzie w windows forms masz wyciąganie z kolekcji kontrolek konkretnego typu i oddzielne operacje na nich?

0
muf napisał(a):

w Twoim ostatnim poście nie ma ani grama treści merytorycznej tylko zwykłe pyskówki :|

W kwestiach merytorycznych, to akurat Ty nie umiesz odpowiedzieć na moje proste pytanie, dlatego wyciągnąłem wnioski.

somekind napisał(a):

a gdzie w windows forms masz wyciąganie z kolekcji kontrolek konkretnego typu i oddzielne operacje na nich?

Wszędzie tam, gdzie to zrobię, bo nie mam innego wyjścia.
Ale najwyraźniej Waszym zdaniem M$ powinien zapewnić oddzielną kolekcję do każdego typu, bo w przeciwnym razie łamie zasadę Liskov...

0
Sarrus napisał(a):

@Pabloss dlaczego metoda Zamiataj nie może być wywoływana w metodzie Pracuj klasy pracownik? Czy to jest inna forma aktywności? Kara?

Kompletnie nie brałem w moim przykładzie pod uwagę logiki tej metody, równie dobrze mogła by się nazywać NiebieskieSlonBiegajacyNaTrabie() :D Chodziło mi generalnie o sposób wywołania takiej metody bez definiowania jej w klasie bazowej a potem nadpisywania. Tutaj koledzy ładnie poradzili jak widzę :)

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