Download presentation
Presentation is loading. Please wait.
Published byAnnabella Oliver Modified over 8 years ago
1
Introduction Advanced OOP CS 440/540 Fall 2016 Kenneth Chiu
2
Requirements What are they? What kinds are there? – Functionality – Performance – Platform/dependencies How are they specified? – API – Documentation – Input files, output files – Performance metrics
3
Design What is a good design? What is a bad design? What makes one design better or worse than another? – Faster – Easier to understand – Easier to modify Is sometimes a slower executing design better than a faster executing design? Can we objectively measure how good a design is?
4
Why Is Software Complex? The problem itself is complex. Difficulty of managing the process. – Two different teams may not be completely in sync on the way that two pieces of code interact, leading to complexity. The flexibility of software. – Creeping featurism. – Changing requirements. The world itself changes. – What’s wrong with incremental changes? – Why not design it right in the first place? “Accidental” vs. essential – Accidental: Interface not quite right might require an adaptor. – Essential: Problem domain is complex.
5
Managing Complexity This course is about managing complexity. – That’s what really distinguishes okay code from great code. What really matters is: How well can you use the language features to manage complexity? – Have you ever said or thought? “I didn’t have time to make it simpler.” It’s hard to make things simple. Strategies to manage complexity? – How is an airplane structured? – Localize it. This helps lead to the things we think of as a good design. – Why does localization help? Complexity is “contained”, so it doesn’t add up across the whole artifact. – Practical strategy for localization is modularization. Interfaces between modules. Internal complexity not exposed. – How do you start to modularize? Decomposition. – Strategies for decomposition? Algorithmic OO
6
Code Reuse Why is code reuse good? How does it help us manage complexity? – What’s wrong with copy-and-paste? – It concentrates (localizes) complexity. How do we get code reuse? Parameterization is crucial. – What is parameterization? – In what ways can code be parameterized?
7
How do we get code reuse? – i = j*a + j*b; … i = j*a + j*b; – i = f(j, a, b); … i = f(j, a, b); – #define xyzzy() i = j*a + j*b xyzzy(); … xyzzy(); #undef xyzzy
8
How do we get code reuse? – for (int i = 0; i < 10; i++) { // Code fragment using three // variables. // … } // … for (int i = 0; i < 100; i++) { // Same code fragment. // … } – loop(10, /* Pass variables */); … loop(100, /* Pass variables */);
9
– // Fragment A if (i l) { // Fragment B, repeated } // Fragment C, repeated – bool less(int i, int j) { return i j; } void doit(int op1, int op2, bool (*cmp)(int, int)) { // Fragment A if ((*cmp)(op1, op2)) { // Fragment B } // Fragment C } doit(i, j, &less); doit(k, l, &greater); Consider a case like this. How do we get code reuse?
10
– // Fragment A if (i l) { // Fragment B, repeated } // Fragment C, repeated – fragA(); if (i l) { fragB(); } fragC(); Another way:
11
– bool less(int i, int j) { return i j; } void doit(int op1, int op2, bool (*cmp)(int, int)) { // Fragment A i = 2*j + k*l; k = j/2; if ((*cmp)(op1, op2)) { // Fragment B } // Fragment C } doit(i, j, &less); doit(k, l, &greater); Still works? // Fragment A i = 2*j + k*l; k = j/2; if (i l) { // Fragment B, repeated } // Fragment C, repeated What if the fragments need access to local variables?
12
Need to pass. bool less(int i, int j) { return i j; } void doit(int &i, int &j, int &k, int &l, double &x, double &y, int &a, int &b, int &c, int op1, int op2, bool (*cmp)(int, int)) { // Fragment A if ((*cmp)(op1, op2)) { // Fragment B } // Fragment C } // … doit(i, j, k, l, x, y, a, b, c, i, j, less); doit(i, j, k, l, x, y, a, b, c, k, l, greater);
13
– fragA(&i, j, k, &l); if (i l) { fragB(a, b, &c); } fragC(&x, &y); Or, in the other solution, looks like: Other ideas?
14
Can wrap the parameters in an object using a local struct. – int i, j; double x, y; int a, b, c; struct Helper { Helper(int &i_, int &j_, int &k_, int &l_, double &x_, double &y_, int &a_, int &b_, int &c_) : i(i_), j(j_), k(k_), x(x_), y(x_), a(a_), b(b_), c(b_) {} int &i, &j; double &x, &y; int &a, &b, &c; void fragA() { /* … */ } void fragB() { /* … */ } void fragC() { /* … */ } } h(i, j, k, l, x, y, a, b, c);
15
It’s usually a bit cleaner looking and concise to just put the variables inside the struct. – struct { int i, j, k; double x, y; int a, b, c; void fragA() { /* … */ } void fragB() { /* … */ } void fragC() { /* … */ } } h; h.i = 0; h.j = 0; h.k = 0; h.x = 3.14; h.y = 2.2; h.a = 2; h.b = 3; h.c = 5; – h.fragA(); if (h.i h.l) { h.fragB(); } h.fragC();
16
So now, rather than this: – fragA(&i, j, k, &l); if (i l) { fragB(a, b, &c); } fragC(&x, &y); We have this: – h.fragA(); if (i l) { h.fragB(); } h.fragC();
17
Rather than passing local variables to helper functions, or storing them in helper objects, we can use a lambda (C++11) to automatically capture them. – std::function ij_less = [&]() { return i kl_greater = [&]() { return k > l; }; auto doit = [&](const std::function &cmp) { // Fragment A if (cmp()) { // Fragment B } // Fragment C }; doit(ij_less); doit(kl_greater); – doit([&]() { return i l; });
18
We can also use lambdas if we want to turn the fragments into functions. – auto fragA = [&]() { /* … */ }; auto fragB = [&]() { /* … */ }; auto fragC = [&]() { /* … */ }; fragA(); if (i l) { frag B(); } fragC();
19
Probably the nicest way is to use lambda’s just for the comparisons: – for (const auto &cmp : std::vector >{ [&]() { return i < j; }, [&]() { return k < l; }, } ) { // Fragment A if (cmp()) { // Fragment B } // Fragment C }
20
We can also just use a macro. – #define xyzzy_doit(op1, op2, cmp) \ /* Fragment A */ \ if (op1 cmp op2 { \ /* Fragment B */ \ } \ /* Fragment C */ – xyzzy_doit(i, j, ) Why the funny prefix? This is actually pretty clean looking. What’s the downside?
21
Hierarchy What is it? A ranking of abstractions. Example? – Employee, manager.
22
Examples Example: A hierarchy of living things. – By region? – Number of legs? – By color? A hierarchy of vehicles. – Brand? – Number of wheels? – Type of engine? – Number of axles? A hierarchy for dishes. – By country? – By style? – By content? Often no one best hierarchy, without considering use cases. MI can help resolve conflicting use cases.
23
Purpose of hierarchies Why? – Maximizes other reuse, improves abstractions. – Code can be oblivious to the difference. – Abstractions and hierarchies go hand-in-hand.
24
Two kinds of hierarchy Consider: – An engine is part of a truck. – A diesel engine is a kind of engine. First is considered part-of, second is considered is-a. What do they correspond to? – Object hierarchies – Class hierarchies So, can you have an object hierarchy without a class hierarchy? How about a class hierarchy without an object hierarchy? – These two hierarchies are orthogonal.
25
Nature of an Object What is an object, in OOP? What is or is not an object? – red? – airplanes? – processes? – Figuring these out is part of analysis phase. What qualities should objects have? – Abstraction – Encapsulation – Modularity – Hierarchy
26
When to Make Things a Separate Class A checking account: – Has a monthly fee. – Does not pay interest. A savings account: – Has no monthly fee. – Pays monthly interest. Should we make these separate classes?
27
Design process: – Determine objects in the domain – Determine operation – Determine state – Then determine abstraction/encapsulation. – Is there a cost to encapsulation? Could you do OOP before C++/Java? Objects are the fundamental building blocks, not algorithms.
28
Summary of Classification/Hierarchies Given any domain (such as dishes), there are many different ways to classify/organize the entities. In code, we can only have a single class organization. – So we have to pick something. – MI can be used to alleviate. Other aspects have to implicit, rather than explicit. – Or sometimes can be represented in the object hierarchy.
29
Abstraction/Encapsulation What is abstraction? What is encapsulation? Is there a difference between the two? Both look similar, if you look at just the actual edits to the code that might be involved. But the goals are different. – Encapsulation: Hiding stuff that is private to the implementation, so the user can’t mess with it, and also so the user doesn’t come to depend on it. (What is bad about the latter?) – Abstraction: Taking a set of interfaces, figuring out what are the key concepts, interactions, methods, etc. Simplify.
30
Abstraction What is it? Abstraction is usually performed over a set of similar classes. Abstraction is simplifying things. – What’s the minimal set of public state and operations that your objects (conforming to the same interface) need to provide to the rest of your code? Principle of least commitment. Abstractions should be minimal.
31
Abstraction is more than just creating a list of operations. – Sometimes there are multiple ways to represent the same thing. What’s the abstraction of a 2-D point? – class Point { get_x(); get_y(); set_x(x); set_y(y); }; – class Point { get_theta(); get_r(); set_theta(t); set_r(r); } How do we solve this? – Represent internally in one of these. Provide all methods. But if we pick the wrong internal representation, then there will be a high conversion cost. – Consider these to be two different abstractions. Pick one of them. Some things are “too abstract” to hope for a computer representation that is ideal.
32
Encapsulation What is it? – Hiding the implementation or other details. Is there a difference between abstraction and encapsulation? – Can you abstract without encapsulating? – Can you encapsulate without abstracting? Flip sides of the same coin.
33
Example Consider a set of shapes: – struct Triangle { double x[3], y[3], z[3]; double area; }; struct Square { double length; }; struct Rectangle { double length, height; }; – [Interactive]
34
Modularity What is it? Concerns should be separated. Why?
35
What is OOA? Analysis is looking at the problem domain, and figuring out how things interact. Let’s say you are doing a payroll program…
36
What is OOD? Design is figuring out how to take your analysis, and put it into code. What are the objects, what methods do they have, etc.
37
Waterfall Model Requirements Analysis Design Implementation
38
Iterative Development Give up trying to get the design right from the beginning. Instead, accept that it’s going to take multiple iterations, and try to make streamline that process.
39
Defensive Programming Most programs are riddled with bugs. Most bugs (like cockroaches) are hidden, unrevealed. When long-hidden bugs show themselves, they are hard to exterminate. Why? – Place where bug shows itself is far removed from where bug actually occurs. – The bug was actually put into the code a long time ago. – Moral: Exterminating bugs is easiest when you catch them in their nest, and when you catch them early. The purpose of defensive programming is to force bugs to show themselves as early as possible, and as close to the origin of the bug as possible. Think about what programmers using your code might do, long after you wrote the code. – They may interpret things slightly differently, and use or modify your code in the wrong way. – Try to force such bugs to reveal themselves early and quickly.
40
Robustness What does “robust” mean? – You can have source robustness. Portable Likely to catch errors that other programmers do. – Is this robust? class String { public: String(const char *s) : str(strdup(s)) { } ~String() { free(str); } private: char *const str; }; – You can have run-time robustness. Likely to respond well to abnormal conditions. Example conditions?
41
Let’s say that you are writing a 100 line program. One of the functions has a potential problem, but you estimate that the chance of it happening is only 1 in 1,000,000 every time the program is run. You figure it’s okay to ignore. – Good idea? – If there are 10,000 such functions, the probably of failure becomes 1 out of 100.
42
static OSStatus SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams, uint8_t *signature, UInt16 signatureLen) { OSStatus err;... if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail;... fail: SSLFreeBuffer(&signedHashes); SSLFreeBuffer(&hashCtx); return err; }
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.