Python obiektowo poprawa kodu

0

Cześć, czy jest ktoś mi w stanie powiedzieć co należy poprawić aby kod był zgodny ze wzorcem Kompozyt ? i drugie pytanko czemu nie mogę wyświetlić całej zawartości tablicy ? Chciałbym aby c.WyswietlWartosc wyświetała wartość całej tablicy czy Opis TypProduktu i Opis OpisuProduktu

from abc import ABC, abstractmethod, abstractstaticmethod

class Koszyk(ABC):
    @abstractmethod
    def Opis(self):
        pass
    
    def dodajProdukt(self):
        pass
    
    
class TypProduktu(Koszyk):
    
    def __init__(self,typ):
        self.typ = typ
        self.tab = []
        
    def Opis(self):
        print(f"Typem produktu jest {self.typ}")
        
    def dodajProdukt(self,Opis_Produktu):
        self.tab.append(Opis_Produktu)
    
    
class OpisProduktu(Koszyk):
    
    def __init__(self, nazwa, tonaz, kalorie):
        self.nazwa = nazwa
        self.tonaz = tonaz
        self.kalorie = kalorie   
        
    def Opis(self):
        print(f"Produkt ten nazyw sie:{self.nazwa} jego waga to:{self.tonaz} posiada {self.kalorie} kalorii")
    
               
        
class Opakowanie(Koszyk):
    
    def __init__(self, typOpakowania):
        self.typOpakowania = typOpakowania
        self.tab = []  
        
    def Opis(self):
        print(f"Opakowanie jest typu {self.typOpakowania}")
        
    def dodajProdukt(self,GotowyTypProduktu, GotowyOpisProduktu):
        self.tab.append([GotowyTypProduktu,GotowyOpisProduktu])
        
    def WyswietlZawartosc(self):
        for i in self.tab:
            print(i.Opis())   
    

a=TypProduktu('Nabial')

b=OpisProduktu('Mleko','10','5')

a.dodajProdukt(b)


c=Opakowanie('Duze')
c.dodajProdukt(a,b)
c.WyswietlZawartosc()

0

Wiem że można dodać jeszcze jedną klasę z metodą set która będzie leciała po obiektach i wyświetała jej Opisy, ale ja chcĘ aby wyświetlała całą wartosć Koszyka czyli c.WyswietlWartosc()

0

Dziękuję za tak gigantyczny odzew :) nie spodziewałem się tylu pomocnych odpowiedzi :)

1
  1. Zacznij nazywać metody z małej litery oraz snake_casem.
  2. Zacznij używać języka angielskiego w kodzie zamiast języka polskiego
  3. Nie podałeś żadnego błędu jaki dostajesz.
  4. W linijce 43 dodajesz do listy tab listę, więc lista będzie wyglądała np. tak: [element1, element2, [element3, element4], element5].
self.tab.append([GotowyTypProduktu,GotowyOpisProduktu])

Natomiast w linijce 47 próbujesz wywołać metodę Opis na elementach z listy tab, ale w linijce 43 dodałeś tam listę.

print(i.Opis())   

Więc dostajesz błąd: AttributeError: 'list' object has no attribute 'Opis'. Bo przecież lista nie ma metody Opis. Musisz dodać pojedynczo te elementy w linijce 43 lub też zrobić konkatenację dwóch list.

  1. Wzorzec kompozyt w ogólności polega na tym, że masz pewne obiekty, które gałęziami lub liśćmi. Gałęzie i liście implementują tę samą metodę. Np. description(). Przy czym gałęzie mogą być opakowaniem na wiele liści lub gałęzi, a liście załóżmy, że nie mają już żadnych referencji na inne liście. Teraz wywołując metodę description() na gałęziach przechodzisz po wszystkich elementach z listy i wywołujesz na nich metodę description().

  2. Wzorzec kompozyt jest używany np. w renderowaniu stron internetowych gdzie masz np. obiekt klasy View. Ten obiekt składa się z wielu obiektów klasy View. Kiedy już sobie stworzysz taki szablon View to chcesz go wyrenderować razem z szablowanami z których ten szablon się składa. Wywołujesz: MainView().render() i ta metoda wywołuje metodę render() na wszystkich szablonach wchodzących w skład tego głównego szablonu.

1

Co do dobrego kodu w pythonie:

  • Jest konwencja języka programowania, więc jak wybierasz jakąś konwencje to się jej trzymaj. Możesz nazywać funkcje od wielkiej litery lub małej, użyj snake_case albo camelCase, ale jak już wybierasz jedną to się jej trzymaj wszędzie.
  • Jest też konwencja języka. Możesz pisać po polsku albo po angielsku, ale pisz w jednym języku wszędzie! Nie rób tak żę raz polski raz angielski. Takie mieszanie jest mega słabe.

Co do samej obiektowości:

  • To że używasz klas abstrakcyjnych w kodzie jest spoko.
  • Zauważyłem że Twoje funkcje albo mają side-effect (np print()). albo zwracają wartość, czyli mają Query-Command Separation. To jest dobre i bardzo obiektowe.
  • Ustawiasz stan obiektów przez konstruktor, to również jest bardzo obiektowe.
  • Nazwy metod są w miare spoko, np dodajProduct() u ciebie faktycznie dodaje produkt. To na plus. Ale nazwa metody Opis() sugeruje że funkcja "zwraca opis", że powinno być return "something", a u Ciebie robi print(). Więc ja bym ją zmienił żeby Opis() zwracał jednak opis.

Co do wzorca kompozyt:

  • We wzorcu kompozyt po prostu chodzi o to, żeby kolekcję jakiś obiektów (mającą 0 elementów, 1 element, lub n elementów) dało się traktować tak jak pojedynczy element tej kolekcji - czyt. mają taki sam interfejs, czyt. np dzielą klasę abstrakcyjną.
  • Moim zdaniem, w Twoim przykłądzie, wzorzec kompozyt ma szczerze mówiąc zastosowanie raczej słabe. Jaką funkcję mógłbyś wykonać zarówno na koszyku jak i na produkcie w tym koszyku. Wydaje się że tylko Opis. Być może chodziło Ci po prostu o polimorfizm, chociaż w tym wypadku to zastosowanie również jest raczej średnio uzasadnione.
  • Twoja hierarchia jest pochrzaniona. U Ciebie TypProduktu jest koszykiem, OpisProduktu jest koszykiem i Opakowanie jest koszykiem.

Ja bym to zrobił bardziej jakoś tak (pisane z palca):

from abc import ABC, abstractmethod

class Item(ABC):
    @abstractmethod
    def Opis(self):
        pass

class Produkt(Item):
    def __init__(self, nazwa, tonaz, kalorie):
        self.nazwa = nazwa
        self.tonaz = tonaz
        self.kalorie = kalorie   

    def Opis(self):
        return f"Produkt ten nazyw sie:{self.nazwa} jego waga to:{self.tonaz} posiada {self.kalorie} kalorii\n"


class GrupaProduktu(Item):
    def __init__(self, grupa):
        self.grupa = grupa
        self.products = []

    def Opis(self):
        return f"Produkt jest {self.grupa}\n" + [p.Opis() for p in self.products]

    def dodajProdukt(self, product):
        self.products.append(product)

class Opakowanie(Item):
    def __init__(self, typOpakowania):
        self.typOpakowania = typOpakowania
        self.grupy = []  

    def Opis(self):
        return f"Opakowanie jest typu {self.typOpakowania}\n" + 
            [g.Opis() for g in self.grupy]

    def dodajProdukt(self, grupa):
        self.grupy.append(grupa)


a=GrupaProduktu('Nabial')
a.dodajProdukt(Produkt('Mleko', 10, 5))
a.dodajProdukt(Produkt('Banany', 8, 5))

c=Opakowanie('Duze')
c.dodajProdukt(a)
print(c.Opis())

Bo żeby to był kompozyt, to wszystkie klasy muszą się posługiwać takim samym interfejsem. Jakbyś miał że jedna klasa ma Opis() a druga WyswietlZawartosc() to to juz nie jest kompozyt.

0

Dziękuje wszystkimi za odpowiedź. Rozjaśniło mi to cechy wzorca kompozyt

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