Filmsysteem voor ticketreserveringen
Vereisten bekijken
- We willen een online filmsysteem voor ticketreserveringen implementeren.
- Een film vertegenwoordigt de basisinformatie van een film.
- Zoals titel, speelduur en prijsinformatie.
- Een vertoning vertegenwoordigt de daadwerkelijke gebeurtenis waarbij het publiek de film bekijkt.
- Met details zoals datum, tijd en volgnummer.
- Mensen reserveren films, maar eigenlijk zouden we moeten zeggen dat ze een specifieke vertoningvan een film reserveren.
- Kortingvoorwaarden
- Of er al dan niet korting wordt verleend op de prijs.
- Volgordevoorwaarde: gebruik het volgnummer van de vertoning om te bepalen of er korting wordt verleend.
- Periodevoorwaarde: gebruik de starttijd van de filmvertoning om te bepalen of er korting wordt verleend.
- Kortingbeleid
- Bepaal het kortingsbedrag.
- Korting in geld: een vast bedrag korting op de reserveringskosten.
- Korting in percentage: een bepaald percentage korting op de normale prijs.
- Per film kan er één kortingsbeleid worden toegewezen, of helemaal geen. Kortingvoorwaarden kunnen een combinatie zijn van meerdere voorwaarden.
- Als er een kortingsbeleid van toepassing is, maar de kortingsvoorwaarden niet worden voldaan, of als er geen kortingsbeleid van toepassing is, wordt er geen korting toegepast.
Naar objectgeoriënteerd programmeren
Samenwerking, objecten, klassen
- Objectgeoriënteerd is gericht op objecten.
- We moeten niet eerst de klassen bepalen en dan nadenken over welke attributen en methoden die klassen nodig hebben.
- We moeten bepalen welke objecten welke toestand en gedrag hebben.
- We moeten objecten niet zien als onafhankelijke entiteiten, maar als onderdeel van een samenwerkende gemeenschap.
Een programmastructuur die de structuur van het domein volgt
- Het domein is het gebied waarin de gebruiker het programma gebruikt om het probleem op te lossen.
<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fe7d22a03-4a24-40e9-8068-bd03b9fd816b%2FUntitled.png?table=block&id=3f1931fc-8ef9-470a-8189-3727146638f6&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/438;" width="2000" height="438"></span>
- Over het algemeen moet de naam van een klasse hetzelfde zijn als de naam van het bijbehorende domeinconcept, of er in ieder geval op lijken.
- De relatie tussen klassen moet zo veel mogelijk overeenkomen met de relatie tussen domeinconcepten, zodat de structuur van het programma gemakkelijk te begrijpen en te voorspellen is.
Klassen implementeren
- Een klasse is verdeeld in een intern en extern gedeelte. Om een goede klasse te ontwerpen, moet je beslissen welke delen openbaar zijn en welke delen verborgen moeten blijven.
- De attributen van een object worden geblokkeerd met private, en de methoden die nodig zijn om de interne toestand te wijzigen, worden opengezet met public.
- Door de interne en externe delen van een klasse te scheiden, wordt de autonomie van het object gewaarborgd, wat de programmeur de vrijheid geeft om te implementeren.
Autonome objecten
- Objecten moeten autonome objecten zijn met een toestand en gedrag.
- Het bundelen van gegevens en functies binnen een object wordt inkapseling genoemd.
- Door middel van toegangscontrole kan de externe beïnvloeding worden beperkt, zodat het object zelf zijn gedrag kan bepalen.
- Het principe van scheiding van interface en implementatie is een belangrijk principe dat moet worden gevolgd bij objectgeoriënteerd programmeren.
- Publieke interface: het gedeelte dat toegankelijk is van buitenaf.
- Implementatie: het gedeelte dat alleen van binnenuit toegankelijk is.
De vrijheid van de programmeur
- De rol van de programmeur is verdeeld in klasseontwikkelaar en clientprogrammeur.
- De klasseontwikkelaar voegt nieuwe gegevenstypen toe.
- De clientprogrammeur gebruikt de gegevenstypen die de klasseontwikkelaar heeft toegevoegd.
- Implementatieverberging
- De klasseontwikkelaar kan de interne implementatie verbergen door alleen de benodigde delen aan de clientprogrammeur te verstrekken.
- De clientprogrammeur hoeft alleen de interface te kennen, waardoor de hoeveelheid kennis die nodig is wordt verminderd.
De samenwerkende gemeenschap van objecten
- Om geld weer te geven, is het beter om het in een object te verpakken, zoals Money, in plaats van gewoon een variabele van het type Long aan te maken. Door objecten te gebruiken, wordt de betekenis duidelijker en kunnen dubbele bewerkingen op één plaats worden uitgevoerd.
- De interactie tussen objecten om een bepaalde functie van het systeem te implementeren, wordt samenwerking genoemd.
Een kort verhaal over samenwerking
- De enige manier waarop een object met andere objecten kan communiceren, is door berichten te verzenden of te ontvangen.
- De eigen manier om een ontvangen bericht te verwerken, wordt een methode genoemd.
- Het onderscheid tussen berichten en methoden is belangrijk, en hier begint het concept van polymorfisme.
Kortingstarief berekenen
Samenwerking starten voor het berekenen van kortingstarieven
- De Movie-klasse bevat geen gedetailleerde logica met betrekking tot het kortingsbeleid, maar deelt deze taken toe aan de DiscountPolicy-interface. Het gebruik van overerving, polymorfisme en abstractie is van cruciaal belang.
Kortingbeleid en kortingsvoorwaarden
<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F7b9b27a5-0dac-4ba7-9552-05b7f8fbdecd%2FUntitled.png?table=block&id=3264f189-6e12-4a55-94d2-75b851320c7a&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/535;" width="2000" height="535"></span>
Overerving en polymorfisme
Afhankelijkheid tijdens compileertijd en runtime
- De afhankelijkheid van de code en de afhankelijkheid tijdens runtime kunnen verschillen.
- Hoe groter het verschil in afhankelijkheid, hoe moeilijker de code te begrijpen is, maar hoe flexibeler en uitbreidbaarder de code wordt.
Programmeren op basis van verschil
- Met behulp van overerving kunnen we snel en eenvoudig nieuwe klassen toevoegen op basis van bestaande klassen en de implementatie van de bovenliggende klasse hergebruiken.
- De methode om een nieuwe klasse te maken door alleen het verschil met de bovenliggende klasse toe te voegen, wordt programmeren op basis van verschil genoemd.
Overerving en interfaces
- Overerving zorgt ervoor dat de onderliggende klasse alle interfaces erft die door de bovenliggende klasse worden aangeboden.
- Een interface definieert een lijst met berichten die een object kan begrijpen.
- Movie stuurt het bericht calculateDiscountAmount naar DiscountPolicy. Voor Movie maakt het niet uit van welke klasse het exemplaar is dat antwoordt, zolang het maar een succesvolle reactie geeft.
- Daarom kunnen zowel AmountDiscountPolicy als PercentDiscountPolicy in plaats van DiscountPolicy samenwerken met Movie.
- Dit proces waarbij de onderliggende klasse de bovenliggende klasse vervangt, wordt upcasting genoemd. Het lijkt alsof de onderliggende klasse automatisch wordt gecast naar de bovenliggende klasse.
Polymorfisme
- Polymorfisme is het vermogen van een object om verschillend te reageren op hetzelfde bericht, afhankelijk van het type object.
- Movie verzendt hetzelfde bericht, maar welke methode er daadwerkelijk wordt uitgevoerd, hangt af van de klasse van het object dat het bericht ontvangt.
- Polymorfisme is gebaseerd op het feit dat de afhankelijkheid van het programma tijdens compileertijd en runtime kan verschillen.
- Polymorfisme bepaalt de uit te voeren methode tijdens runtime, dus het wordt late binding of dynamische binding genoemd.
Interfaces en polymorfisme
- Als we alleen de interface willen delen en de implementatie niet hoeven te delen, kunnen we in plaats van een abstracte klasse een interface gebruiken.
Abstractie en flexibiliteit
De kracht van abstractie
- Voordelen van abstractie
- Als we alleen naar de abstractielagen kijken, kunnen we het beleid van de vereisten op een hoger niveau beschrijven.
- Het ontwerp wordt flexibeler.
Flexibel ontwerp
- Abstractie voorkomt dat het ontwerp gekoppeld raakt aan specifieke situaties, waardoor een flexibel ontwerp kan worden gecreëerd.
Abstracte klassen en interface trade-off
- Momenteel is NoneDiscountPolicy eigenlijk niet nodig, omdat de calculateDiscountAmount()-methode van DiscountPolicy al 0 retourneert als er geen kortingsvoorwaarden zijn, dus er is geen probleem. Maar vanuit het perspectief van de gebruiker moet de gebruiker een None-beleid invoeren als er geen kortingsbeleid is in de Movie-parameter, dus het is toegevoegd.
- Daarom, als we de NoneDiscountPolicy-klasse aanpassen zoals hieronder, is het gemakkelijker te begrijpen.
- Zoals hierboven weergegeven, wordt DiscountPolicy geabstraheerd tot een interface, en wordt deze opgesplitst in NoneDiscountPolicy, die de implementatie ervan is, en DefaultDiscountPolicy, die een algemeen kortingsbeleid vertegenwoordigt.
<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F712983a9-3937-4265-82fe-66a144c44a0f%2FUntitled.png?table=block&id=f5ca651c-d03c-4a6c-97e9-7443ee5649a0&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/886;" width="2000" height="886"></span>
- Het kan zijn dat je denkt dat het toevoegen van een interface alleen voor NoneDiscountPolicy niet efficiënt is in verhouding tot de toegenomen complexiteit.
- Je moet je realiseren dat alles wat te maken heeft met implementatie een onderwerp kan zijn van een trade-off en dienovereenkomstig ontwerpen. Dat wil zeggen, alle code die je schrijft moet een goede reden hebben.
Codehergebruik
- Overerving kan worden gebruikt om code te hergebruiken.
- Maar voor codehergebruik is het beter om compositie te gebruiken dan overerving.
- De manier waarop Movie momenteel de code van DiscountPolicy hergebruikt, is compositie.
- Als we Movie als bovenliggende klasse beschouwen en deze splitsen in AmountDiscountMovie en PercentDiscountMovie, dan gebruiken we overerving.
Overerving
- Nadelen van overerving
- Schendt inkapseling.
- Je moet de interne structuur van de bovenliggende klasse kennen.
- De kans is groot dat de onderliggende klasse ook moet worden gewijzigd wanneer de bovenliggende klasse wordt gewijzigd.
- Maakt het ontwerp minder flexibel.
- De relatie tussen de bovenliggende klasse en de onderliggende klasse wordt tijdens compileertijd bepaald.
- Het is niet mogelijk om het type object tijdens runtime te wijzigen.
- Maar met compositie kan het gebruikte object worden vervangen door een methode zoals chageDiscountPolicy() tijdens runtime.
- Schendt inkapseling.
Compositie
- De methode om code te hergebruiken via berichten die zijn gedefinieerd in een interface, wordt compositie genoemd.
- Het maakt inkapseling mogelijk en onderhoudt een losse koppeling.
- Voor polymorfisme met hergebruik van interfaces moeten overerving en compositie worden gecombineerd.
- Bijvoorbeeld, de DiscountPolicy-interface kan alleen worden geïmplementeerd met overerving.
Bron
- Objecten
Reacties0