1 / 31

Dobry kod OO

Dobry kod OO.

Télécharger la présentation

Dobry kod OO

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Dobry kod OO

  2. S.O.L.I.D5 podstawowych wzorców dotyczących programowania zorientowanego obiektowozdefiniowane przez Roberta C.Martina(szefu Object mentor Inc., międzynarodowy konsultant do spraw rozwoju oprogramowania, przewodniczył grupie odpowiedzialnej za stworzenie „Agile software development”, twórca książek takich jak: „Designing Object-Oriented C++ Applications using the Booch Method”,„Agile Software Development: Principles, Patterns and Practices”,„Clean Code”)

  3. SRP – Single ResposibilityPrinciple • Jeden powód do zmian! • Pozwala na separację poszczególnych modułów • Jest jedną z najprostszych zasad ale jedną z najtrudniejszych do poprawnego zastosowania • Szukanie i separacja odpowiedzialności jest tak naprawdę wszystkim o co chodzi w tworzeniu oprogramowania

  4. Aplikacja do geometri analitycznej Rectangle + draw() + area() : double Aplikacja graficzna GUI

  5. Aplikacja do geometri analitycznej Aplikacja graficzna Geometric Rectangle + area() : double Rectangle + draw() GUI

  6. interface Modem { public void dial(String pno); public void hangup(); public void send(char c); public char recv(); }

  7. <<interface>> Data Channel + send(:char) + recv() : char <<interface>> Connection + dial(pno : String) + hangup() Modem implementation

  8. OCP – Open-ClosedPrinciple • Elementy oprogramowania (klasy, moduły, funkcje itd.) powinny być otwarte na rozszerzanie, ale zamknięte na modyfikację. • Kiedy pojedyncza zmiana w kodzie wywołuję łańcuch innych zmian w modułach zależnych oznacza to „zły” projekt • Powinno się projektować moduły, które nigdy się nie zmieniają

  9. Client Server Zamknięty klient

  10. Client Abstract Server Server Otwarty klient

  11. Aplikacja rysująca kółka i kwadraty • Aplikacja posiada listę kółek i kwadratów • Kółka i kwadraty muszą być rysowanę zgodnie z kolejnością na liście

  12. enum ShapeType {circle, square}; struct Shape { ShapeType itsType; }; struct Circle { ShapeType itsType; double itsRadius; Point itsCenter; }; struct Square { ShapeType itsType; double itsSide; Point itsTopLeft; }; void DrawSquare(struct Square*) void DrawCircle(struct Circle*);

  13. typedef struct Shape *ShapePointer; voidDrawAllShapes(ShapePointer list[], int n) { int i; for (i = 0; i < n; i++) { struct Shape* s = list[i]; switch (s->itsType) { case square: DrawSquare((struct Square*)s); break; case circle: DrawCircle((struct Circle*)s); break; } } }

  14. class Shape { public: virtualvoid Draw() const = 0; }; class Square : public Shape { public: virtualvoid Draw() const; }; class Circle : public Shape { public: virtualvoid Draw() const; }; void DrawAllShapes(Set<Shape*>& list) { for (Iterator<Shape*> it(list); it; it++) (*it)->Draw(); }

  15. class Shape { public: virtualvoid Draw() const = 0; virtualbool Precedes(const Shape&) const = 0; bool operator<(const Shape& s) {return Precedes(s);} }; void DrawAllShapes(Set<Shape*>& list) { OrderedSet<Shape*> orderedList = list; orderedList.Sort(); for (Iterator<Shape*> it(orderedList); it; it++) (*it)->Draw(); } bool Circle::Precedes(const Shape& s) const { if (dynamic_cast<Square*>(s)) returntrue; else returnfalse; }

  16. class Shape { public: virtual void Draw() const = 0; virtual boolPrecedes(const Shape&) const; booloperator<(const Shape& s) const {return Precedes(s);} private: static char* typeOrderTable[]; }; char* Shape::typeOrderTable[] = { “Circle”, “Square”, 0 };

  17. bool Shape::Precedes(const Shape& s) const { const char* thisType = typeid(*this).name(); const char* argType = typeid(s).name(); bool done = false; int thisOrd = -1; int argOrd = -1; for (int i = 0; !done; i++) { const char* tableEntry = typeOrderTable[i]; if (tableEntry != 0) { if (strcmp(tableEntry, thisType) == 0) thisOrd = i; if (strcmp(tableEntry, argType) == 0) argOrd = i; if (argOrd > 0 && thisOrd > 0) done = true; } else done = true; } return thisOrd < argOrd; }

  18. OCP wiąże się z kilkoma innymi utartymi zasadami • Wszystkie zmienne klasy powinny być prywatne

  19. Co gdy dane pole nigdy się nie zmieni? Czy istnieje powód, żeby czynić je polem prywatnym? class Device { public: bool status; //status ostatniej operacji na //urządzeniu };

  20. class Time { public: int hours, minutes, seconds; Time& operator-=(int seconds); Time& operator+=(int seconds); bool operator< (const Time&); bool operator> (const Time&); bool operator==(const Time&); bool operator!=(const Time&); };

  21. Żadnych zmiennych globalnych – Nigdy Żaden moduł, który zależy od zmiennej globalnej nie może zostać zamknięty względem innego modułu, jeśli ten inny moduł korzysta z tej zmiennej.

  22. LSP – Liskov Substitution Principle • Definicja Barbary Liskov: Jeśli dla każdego obiektu o1 typu S istnieje obiekt o2 typu T, taki że dla każdego programu P zdefiniowanego w kontekście typu T, zachowanie programu P pozostaje niezmienione kiedy o1 jest podmieniane obiektem o2, to prawdziwe jest, że typ S jest podtypem typu T. • Funkcje, które używają wskaźników lub referencji do klas bazowych muszą być w stanie używać obiektów klas dziedziczących po klasach bazowych bez dokładnej znajomości tych obiektów

  23. LSP • Jeśli twój kod oczekuje jakiejś klasy, to zamiast niej powinieneś móc podstawić dowolną klasę z niej dziedziczącą bez zmieniania żadnych oczekiwanych zachowań. • Jeśli przeciążasz metodę, napisz ją tak, by użyta polimorficznie działała poprawnie

  24. Klasyczny problem kwadratu i prostokąta classRectangle { protectedintm_Width; protectedintm_Height; public voidSetWidth(intwidth) { m_Width= width; } public voidSetHeight(intheight) { m_Height= height; } public intGetWidth() { returnm_Width; } public intGetHeight() { returnm_Height; } public intGetArea() { returnm_Width * m_Height; } }

  25. classSquare: Rectangle { public voidSetWidth(intwidth) { m_Width = width; m_Height = width; } public voidSetHeight(intheight) { m_Width = height; m_Height = height; } } Rectangle r = new Square(); r.SetWidth(5); r.SetHeight(10); int area = r.GetArea();

  26. public classUser{ protectedString login; protectedStringpassword; protected List modules; publicvoidaddAccessToModule(Module module) { modules.add(module); } public booleancanAccess(Module module) { returnmodules.contains(module); }

  27. public classAdminextendsUser { private List administeredModules; public booleancanAccess(Module module) { returnadministeredModules.contains(module); } } public voidsubscribeToEvents(Useruser, Module module) { if (! user.canAccess(module)) { user.addAccessToModule(module); } module.sendEventsTo(user); }

  28. LSP • Design by Contract. Klasy definiują warunki wejściowe i wyjściowe metod • Odpowiednia dokumentacja.

  29. ISP – InterfaceSegregationPrinciple • Klienci nie powinni być zmuszani do bycia zależnymi od metod, których nie używają. • Likwiduje „grube” interfejsy

  30. interfaceIWorker { voidWork(); voidEat(); } classWorker: IWorker { public voidWork() { } public voidEat() { } } class Robot: IWorker { public voidWork() { } public voidEat() { thrownewNotImplementedException(); } }

  31. interfaceIWorkable { public voidWork(); } interfaceIFeedable { public voidEat(); } classWorker: IWorkable, IFeedable { public voidWork() { } public voidEat() { } } class Robot: IWorkable { public voidWork() { } }

More Related