<p>I found a Python class to be so simple to write (for &quot;mundane&quot; tasks), that they can grow naturally out of a desire to simplify and refactor code in development. It is very much a <em>pragmatic</em> bottom-up approach; you were expecting to hack some simple code for a particular purpose, then it grows a bit and you find you have several functions handling &quot;structures&quot; that were tuples or arrays or even globals.  Suddenly, you see the light and create a class, and the code size gets divided by 2 or more, and is <em>so much simpler</em>.</p>
<p>This is an easy way to argue for OOP, by taking some &quot;flat&quot; concrete existing code and looking for the abstraction that could be made, moving the data out of the function parameters, into the class, and using <code>self</code>.</p>
<p>Things like inheritance can similarly be discovered almost naturally; you use an existing class that doesn't quite do what you want and you need to change it; instead of copying and modifying it, you subclass and change or add a method.</p>
<p>For concrete examples, you can look at computer hardware itself. At a low level, registers are often partitioned into several disparate functions. If you want to set a feature bit to 1, you need to shift it left 20 bits, read the current value of the register, mask out bits 0 to 5 as they are &quot;write 1 to clear&quot;, and so on. Try emulating a serial port 16550 uart; it is good for the soul. And, of course, if you use MicroPython running on a real microprocessor, you could probably even try out your code.</p>

CC BY-SA 4.0
2021-02-05T15:10:27.273Z
2021-06-01T03:34:05.297Z
2021-06-01T03:34:05.297Z
meuh
<p>My go-to example for both data modeling and OOP (which in both cases revolve around a kind of normalization), is a <strong>video rental store</strong>. It's maybe a very dated example, feel free to change it to a library or a rental store for other things, but I find that the video store example both highlights the intricacies of OOP and data normalization, while at the same time being a very simple context to grasp.</p>
<p>The main goal is to build up to a three table/class diagram: <code>Customer</code>, <code>Video</code> and <code>Rental</code> (which is the cross table between customers and videos).</p>
<p>The rest of this answer is just tips on how to relate specific OOP basics to the example at hand.</p>
<hr />
<p><strong>Why objects?</strong></p>
<p>Well, how would you store your video data, if you want to track three things for a rental: the customer name, address, video name, and expected date of return.</p>
<p>Ask the students to write a very simple program that is able to tell you that Alice rented Antz, Bob rented Bee Movie, and Charlie rented Cars. Let them rely on some reusable <code>PrintRentalInfo</code> method, but allow them to define the method parameters as they see fit.</p>
<p>Students who haven't yet seen OOP will use four distinct arrays and rely on the fact that one video is found on the same index in all four arrays. Explain to them that instead of having a &quot;bag&quot; of customer names, a &quot;bag&quot; of addresses, a &quot;bag&quot; of video names, and a &quot;bag&quot; of return dates is not really easy to work with. Suggest the idea that instead of making a &quot;bag&quot; per data field, it would make more sense if we made a &quot;bag&quot; per rental.</p>
<p>Build the <code>Rental</code> class with the four properties. Build the same application as they did, but using OOP. This will show them object initialization, how different objects have the same structure but individually unique content, and how you can pass an object around (as opposed to multiple method parameters of primitive types).</p>
<p>Really highlight how easy it is that you can move this rental &quot;bag&quot; around from method to method, keeping all relevant information together.</p>
<hr />
<p><strong>Why more than one class?</strong></p>
<p>A fourth customer appears. Her name is also Alice. You run into an issue here, because now you're unable to tell <em>which</em> Alice has rented which videos, and you don't want to fine the wrong Alice.</p>
<p>Also, the original Alice has called us to let us know her address has changed. Point out the difficulty of having to go through all the rentals and figuring out that you can't just blindly change &quot;old_address&quot; to &quot;new_address&quot;, because there may be other customers living on that same address who did not move with Alice. Also, you can't rely on the name either, as the fourth Alice has already made some rentals too.</p>
<p><em>If the students keep protesting that you could do it based on the combination of name and address, as what happens if those two Alices live on the same address, and only one of them moves.</em></p>
<p>Suggest to the students that it would make a lot of sense if we had a separate list of all our customers and their addresses, so we could tell them apart by more than just their name, and easily change one person's details.</p>
<p>Goal: build a <code>Customer</code> class, and change <code>Rental</code> so it includes a <code>Customer</code> property as opposed to name/address properties.</p>
<p>Focus: very much highlight how you can have two <strong>different</strong> customer objects, even when their names and addresses are the same.</p>
<p>Extra: You can take the same approach to creating the <code>Video</code> class, so you can track the specific videos you have. Maybe leave this as an exercise to the students, as this is much of the same as before.</p>
<hr />
<p>From this point on, you can expand the business logic based on what you want to showcase.</p>
<ul>
<li><strong>Inheritance</strong> - Maybe the store rents <code>Video</code> and <code>Game</code>, but you still want <code>Rental</code> to be able to link to either of them (using the base <code>RentableObject</code> class)</li>
<li><strong>Interface</strong> - You can use the same example as inheritance.</li>
<li><strong>Data normalization</strong> - How would we go about both tracking the movies we have available, and the individual physical cassettes (we could have multiple of the same movie)? How would be be able to track fines that a customer has incurred, and which of them they have already paid?</li>
<li><strong>Data transformation</strong> - Our boss wants us to print a weekly report on all rentals made, rentals returned, incurred fines, and fines from before which <em>still</em> haven't been paid.</li>
<li><strong>Reference vs value</strong> - Add a <code>Price</code> to both the <code>Video</code> and <code>Rental</code>. Showcase how you set <code>rental.Price</code> based on <code>video.Price</code>, but when <code>video.Price</code> later changes, <code>rental.Price</code> is untouched. Now repeat the same exercise with a reference object (e.g. changing the customer's name).</li>
</ul>
<p>I find that the context for this example is very easy to grasp, and has a lot of opportunity for expansion. This could grow into a long-term project that you keep expanding, which can be a valuable lesson if you want to teach your students about how to handle changing requirements and the benefits of clean coding, or maintenance and legacy development.</p>

CC BY-SA 4.0
2021-06-02T10:17:29.993Z
Thanks for the ideas! Some suggestions, a.  I use python so I believe we will first use dictionary not array to build the first version b. this is a good example to introduce 'id' concept, id for customer, id for video.
Qiulang 邱朗
CC BY-SA 4.0
2021-06-02T10:20:50.973Z
@Qiulang: Absolutely. While this does muddy the line a bit between OOP and data normalization, these two concepts are thematically linked and often feed into each other in actual business projects, so I very much like that you learn a bit of both at the same time.
Flater
CC BY-SA 4.0
2022-01-06T12:02:02.897Z
A video store is a nice example of an object-oriented design. But how do you use it? Are you going to keep an array of customers, and at random times they visit the store? What are those times? How do you make this realistic? That driver program may actually be harder to program than the classes. And how do you determine that your whole program does what it's supposed to do?
Victor Eijkhout
CC BY-SA 4.0
2022-01-06T12:31:53.757Z
@VictorEijkhout: I'm not quite sure what you're focusing on here. The answer is focused on an example that drives the design of a video rental application, not a simulation of how it will be used during a real day. How to realistically simulate usage in a specific scenario is a completely different topic and not at all something OOP-learners should be concerned by. Part of this exercise is to let the students find a solution and then showcasing betters ways of doing the same thing; which precludes giving a pre-formatted input as this would start revealing the intended design.
Flater
CC BY-SA 4.0
2022-01-06T12:36:05.677Z
@VictorEijkhout: Your last question implies you're bring up TDD (or some kind of testing at least). While I appreciate the value of TDD (and testing in general), the first introduction to OOP is not the right time to also introduce testing, nor should the two be merged into a single practical exercise for the students.
Flater
CC BY-SA 4.0
2022-01-06T14:25:09.970Z
@Flater I wouldn't go as far as doing TDD or Unit Testing, but I'm sticking to my point that if you assign a project, you should outline not only the design but some usage scenarios. I don't know if you're an active teacher, but it's my experience that students will happily do insufficient "testing" whether their code is actually sensible.
Victor Eijkhout
CC BY-SA 4.0
2022-01-06T14:30:15.117Z
@VictorEijkhout: You're thinking of a much bigger exercise than what I am describing here. The only part where I suggested that students try it themselves (before showing them how OOP can do it better) would take around an hour (maybe two) to complete. Everything after that is described as the teacher working through the OOP implementation, not the students. It's of course a good idea to also give students some exercises themselves but I never claimed that my answer contains a complete curriculum; just a practical example that easily highlights what OOP can be leveraged for.
Flater
CC BY-SA 4.0
2022-01-06T14:34:25.683Z
@VictorEijkhout: The focus in this answer is also not on UI or end-user interaction, but rather how to model the internal workings of the application (specifically its data structure) based on a straightforward use case. The use case is very intentionally chosen to be both trivial to understand (person rents thing), and easy to adjust its complexity to gradually introduce extra requirements which highlight more advanced OOP principles (examples provided in the answer at the end). If you want to review and test every student's work, by all means; but that is simply not what this focuses on.
Flater
CC BY-SA 4.0
2021-06-02T09:36:16.583Z
2021-06-02T09:36:16.583Z
Flater
<p>How about a boring*, but realistic, commercial example? When the students leave the &quot;hallowed halls&quot; and become entrepreneurs in start-ups, they will be faced with the relationships between Customer, Product, and Sale (Transaction).</p>
<p>By keeping all of the Product data (for example) 'together', we introduce the advantage of encapsulation over a basic data structure, eg array. There is scope for hierarchies (later).</p>
<p>Per earlier &quot;composition&quot; responses, when we look at an Address we see that each Customer must have one, oh wait, more than one if his/her billing address is distinct from the delivery address. So, if an Address is part of a Customer, should Customer &quot;inherit&quot; from Address? (&quot;is a&quot; cf &quot;has a&quot;!) What about the difference between a personal customer and a corporate?</p>
<p>Do both have a name, and address, ...? How are they similar/where do they differ? How do we keep track of the individual from the Corporation with whom we are dealing?</p>
<p>What happens when we make a sale? Is this data to be part of the purchasing-Customer's object, or the Product object - or objects, or what? Thus, &quot;Interfaces&quot; (in some languages), an invitation to expand the SRP into micro-services, drop into APIs...</p>
<p>There's plenty of scope for SOLID principles, best practices, language differences, and all-the-fun-of-the-fair. Meantime, you could 'dress up' problems to make the toy-examples seem 'real' any-which-way; and the students are learning 'how the world works' and thus (hopefully) enthused to progress.</p>
<ul>
<li>personal opinion: can't imagine how Pathlib avoids the &quot;boring&quot; criterion (besides it has its own struggles with 'the concrete', given its abstraction from the OpSys - which is already an abstraction ... Alice, rabbit hole, Toto != Kansas...)</li>
</ul>

CC BY-SA 4.0
2021-01-01T21:46:39.140Z
Actually, no, a customer is not a subclass of address. That makes no sense. If it makes no sense then the software is conceptually broken and can't be maintained. One of the worst ideas ever to appear in an elementary book was to make Cylinder a subclass of Circle, just because the Circle class already had some fields that a Cylinder also needs.
Buffy
CC BY-SA 4.0
2021-01-02T06:07:43.120Z
path is something they know and they notice the difference between windows and unix. Teaching pathlib really teaching something they can learn, think, explore. So it is not boring (my opinion).
Qiulang 邱朗
CC BY-SA 4.0
2021-02-04T22:21:51.243Z
Apologies @Buffy, it may not have been apparent that I use a Socratic approach towards trainees' learning. You and I both know about sub-classing and composition!
d-n
CC BY-SA 4.0
2021-06-02T09:40:12.527Z
@Buffy: The inheritance idea was phrased as a question for the teacher to explore with the students. Not as the right answer. Exploring bad ideas that most (if not all) developers intuitively think of before they understand why it's a bad idea, is a really good and pro-active way to help your students get ahead of the curve as opposed to knowingly and unguidedly letting them fall into the trap.
Flater
CC BY-SA 4.0
2021-01-01T21:03:49.853Z
2021-01-01T21:03:49.853Z
d-n
<p>I expect to update this a few times and hope to eventually have a long answer.</p>
<p>But let me start by explaining some things that you may already be aware of, but other readers may not.</p>
<p>First, OO programming is not, fundamentally, about inheritance and too many books and authors fail to understand that. Moreover, they use inheritance in a dreadful way that makes software hard to understand and harder to maintain.</p>
<p>For example, note that the Linnaeus style hierarchy of the biological world is almost entirely one of &quot;interfaces&quot; and not even &quot;abstract classes&quot;, much less concrete classes. There are no instantiated &quot;mammals&quot;, for example. It is only at the leave of the hierarchy that things actually exist, other than as ideas. There is some genetic continuity, of course.</p>
<p>Second, there are some principles that can guide you in writing and teaching OO design, but they require discipline. And part of that discipline is to control the situations in which you &quot;break&quot; the rules.</p>
<p>My first advice for anyone wanting to be an OO programmer is not to think in terms of inheritance, but, rather, of composition. Complex things (objects) are <em>composed</em> of other things (objects) that are a bit simpler than the containing object and provide it some essential service. If you write classes where all (or even most) of your instance variables are language primitives, then you don't really get it. And if those instance variables (objects or primitive) have a lot of getters and setters, then you aren't doing OO Programming at all.</p>
<p>In fact, making the above mistakes, requires that the programmer keep track of all details at all points of the program where OO is designed to capture decisions so that they needn't be &quot;checked&quot; again. Set it and forget it, so to speak.</p>
<p>So, if you want to build an automobile, don't think of it as a subclass of vehicle (which gains you nothing: a personal drone and a battleship are both vehicles). Think of it instead of being composed of various parts: engine, transmission, controls, accommodations, etc. And those parts are, themselves, composed of parts. An engine <em>has</em> igniters and pistons, exhaust, etc. Many of those are composed of parts also. It is only at the lowest, simplest level that you build with primitives.</p>
<p>Two of the principles that are worth keeping in mind and following almost always are the <a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle" rel="nofollow noreferrer">Liskov Substitution Principle</a> and the <a href="https://en.wikipedia.org/wiki/Law_of_Demeter" rel="nofollow noreferrer">Law of Demeter</a>.</p>
<p>The first suggests that if you extend a class with a subclass you don't also extend the public interface of the subclass. Then all subclass objects are substitutable, differing in behavior but not in interface. Demeter, on the other hand, forces you to write more explicit code that makes relationships clear to a reader. Of course it also forces you to introduce more names, and if they are <em>intention revealing names</em> then your code is clearer.</p>
<p>The Liskov principle, of course is one of the elements of <a href="https://en.wikipedia.org/wiki/SOLID" rel="nofollow noreferrer">SOLID</a> which you also need to incorporate into your thinking.</p>
<p>In my own programming I'm very faithful to Liskov, also defining Interfaces for most things before I write classes. I'm less faithful to Demeter in the heat of battle, cascading messages. But then I sometimes also need to unravel those a.b.c.d sorts of cascades to figure out what I really mean.</p>
<p>One goal I have in writing OO code is to seek to write only very short methods with a minimum of structure. In other words I try to minimize <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity" rel="nofollow noreferrer">Cyclomatic Complexity</a>. My palms start to get itchy after the fourth statement in a method or if the complexity level reaches three. I can't always get away with that, but it is a goal. The solution is to refactor complexity mercilessly. Factor out methods, of course, but also &quot;parts&quot;, creating new classes to manage the complexity. Even if many of those classes are Singletons the code is usually improved and having the goal in mind from the start, means that the refactoring step is less needed.</p>
<p>Design patterns are tools that you need to be an effective programmer in most OO languages. Especially helpful ones are Strategy, Decorator, Observer, and Iterator. Most of these are actually used to build the various Java libraries.</p>
<hr />
<p>Now, to get to the actual question asked here. But note that a lot of learning can take place even if the students never reach completion of the project in the allotted time. An agile approach (Extreme Programming, say, with you as &quot;Customer&quot;) to development leaves them with <em>some</em> functionality even if not all specifications are implemented.</p>
<h3>Dungeon Game</h3>
<p>Build a text based dungeon game. The main objects are characters (people), places, and things. The places are organized in some sort of map, maze, or grid. Things happen when characters enter places. Characters find and carry things. The things have actions, depending on the kind of thing. A &quot;spell&quot; is a &quot;thing&quot; whose action might depend on context. A &quot;transporter&quot; object might work differently in different rooms (strategy objects).</p>
<p>Note that the classic board game <a href="https://en.wikipedia.org/wiki/Snakes_and_ladders" rel="nofollow noreferrer">Chutes (or Snakes) and Ladders</a> is a simplified version of this. A text based version avoids a lot of complexity.</p>
<h3>Calculator</h3>
<p>A calculator has parts such as keys and the display. Less visible are the internal memory, possibly a stack. Even the operations can be objects. The behavior of the keys changes, depending on the state of the computation (Strategy pattern). It is possible to build a simple calculator without a single IF statement, actually.</p>
<h3>Abstract Computer with an Assembly language</h3>
<p>A Stack Based computer processor simulation is pretty straightforward. There may be accumulators and such, but a single stack on which all operations are done is simple and complete. The operations can be objects (parts). One advantage of this example is that most of the necessary methods can be very short. A program can be read with a Java Scanner object. It needs a program counter at least and possibly a frame pointer if the language is to support subroutines.</p>
<h3>Sticky Notes (I haven't tried this)</h3>
<p>An application that lets users keep notes and cross reference and organize them. Some classes might be Notes, Keywords, Connections, Lists.</p>
<h3>Jeopardy</h3>
<p>A simulator for the jeopardy game from TV. Categories, Answers, Questions, Teams, Scores.</p>
<p>(Back soon, maybe).</p>

CC BY-SA 4.0
2020-12-31T15:34:20.087Z
I have been struggling to a find a way teach OO because I have my doubt. Check my question here https://softwareengineering.stackexchange.com/questions/419122/does-oop-overemphasize-the-importance-of-noun-and-thus-put-action-verb-in-the-le
Qiulang 邱朗
CC BY-SA 4.0
2021-01-01T02:38:44.777Z
I am quite familiar with http://todomvc.com/ I probably can adapt it to my teaching.
Qiulang 邱朗
CC BY-SA 4.0
2021-01-01T13:18:53.283Z
There are links to and explanations and examples of MVC (in Java) here: http://csis.pace.edu/~bergin. Sadly, the applet version no longer runs on the web.
Buffy
CC BY-SA 4.0
2021-01-01T15:27:55.780Z
todomvc is not really about mvc but the the choices and the comparison of different web technologies to implement a todo list. I mentioned because you mentioned Sticky Notes.
Qiulang 邱朗
CC BY-SA 4.0
2021-01-13T04:55:16.203Z
I found an interesting answer Alan Kay gave and updated my question again.
Qiulang 邱朗
CC BY-SA 4.0
2020-12-31T14:53:05.470Z
2021-06-02T10:49:32.690Z
2021-06-02T10:49:32.690Z
Buffy
<p>I have taught my high school students to write some simple python scripts, taking some ideas from <a href="https://automatetheboringstuff.com/" rel="nofollow noreferrer">&quot;Automate the Boring Stuff with Python&quot;</a>, e.g. changing file names in a folder to a specific naming pattern.</p>
<p>My next goal is to teach them object-oriented concepts and if possible give them some &quot;real&quot; examples to try themselves. But most of the materials I find (most of google's top search results) about OO programming (not just python) are laden with poor examples, if I may say so. I really don't like to use car/vehicle or animal/dog to teach them the OO concept and OOP.</p>
<p>A. it is boring (you know high-school kids)<br />
B. it has no real use.<br />
C. as one comment said &quot;they are fatally flawed.&quot;  (But if you really like to use the animal example, check this <a href="https://softwareengineering.stackexchange.com/questions/205459/object-oriented-design">&quot;Object-Oriented Design&quot;</a>)</p>
<p>I plan to use <a href="https://docs.python.org/3/library/pathlib.html" rel="nofollow noreferrer">pathlib</a> (btw, they already have a basic idea of the difference between Windows and UNIX)</p>
<p><a href="https://i.sstatic.net/jvahy.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/jvahy.png" alt="pathlib" /></a></p>
<p>GUI development could be another good example to teach OOP but I don't want to teach them GUI yet.</p>
<p>Any suggestion to introduce OO with the &quot;real&quot; example?</p>
<p>BTW, I’m not a strong advocate of object-oriented programming. But the <code>pathlib.Path</code> class is a useful abstraction especially compared with os.path, although the high school students are unlikely to appreciate that.</p>
<p>---- update ----</p>
<p>I find the python logging module is another good example, but it seems too complicated for non-experienced programmers.</p>
<p>When using the logging module we mainly use 3 objects, <strong>Logger, Handler, Formatter</strong>. Logger is the <strong>facade</strong>, as <a href="https://docs.python.org/3/howto/logging.html#loggers" rel="nofollow noreferrer">https://docs.python.org/3/howto/logging.html#loggers</a> said,</p>
<blockquote>
<p>Logger objects have a threefold job. First, they expose several methods to application code so that applications can log messages at runtime. Second, logger objects determine which log messages to act upon based upon severity (the default filtering facility) or filter objects. Third, logger objects pass along relevant log messages to all interested log handlers.</p>
</blockquote>
<p>Handler is a good example to use <strong>inheritance</strong> <a href="https://docs.python.org/3/howto/logging.html#useful-handlers" rel="nofollow noreferrer">https://docs.python.org/3/howto/logging.html#useful-handlers</a> and handlers use formatters, which hide the complexity of LogRecord, to the format log message.</p>
<p>In addition to these classes, there are a number of <a href="https://docs.python.org/3/library/logging.html#module-level-functions" rel="nofollow noreferrer">module-level functions</a> for convenient use.</p>
<p>Overall it is a good example of using <strong>composition</strong> and aggregation.</p>
<p>But I am not an expert on the python logging module, I hope someone who is familiar with the python logging module may add an answer to my question.</p>
<p>--- update 2 ----</p>
<p>I found Alan Kay answered the question <a href="https://qr.ae/pNDvTp" rel="nofollow noreferrer">“What are the five features of the object-oriented paradigm that you consider to be important for good software engineering practice?</a>” with these words, in my opinion, resonate with the answer Buffy gave. But how to convey these ideas to high school students or non-experienced programmers is another challenge,</p>
<blockquote>
<p>a “part” construct that can protect it's inside from its outside, and
vice versa</p>
<p>a “communications” construct that can convey interactions and deal
with dependencies</p>
<p>a “system” construct that is a combination of parts and communications
that can fit in a part recursively, and everything is made this way</p>
<p>the “messages” that are communicated are also in terms of the systems</p>
<p>the system that is being made is made with the same kinds of system
...</p>
</blockquote>
<p>--- update 3 ---</p>
<p>The recent log4j security flaw made me come back to my own although my question has nothing to do with log4j. I know python logging module is <a href="https://realpython.com/python-logging/" rel="nofollow noreferrer">adopted from Log4j</a>, so I think this can be used as a good example to how different programming languages borrow the idea from each other. If the students have some knowledge about java, I may consider to introduce them this old article &quot;<a href="https://bitworking.org/news/2006/08/python_isnt_java_without_the_compile/" rel="nofollow noreferrer">Python isn't just Java without the compile</a>&quot;</p>
<p>BTW, Buffy gave answer about calculator as an example to practice OO, but I will argue it will depends on how you design the question and the project, e.g. here &quot;<a href="https://www.digitalocean.com/community/tutorials/how-to-make-a-calculator-program-in-python-3" rel="nofollow noreferrer">How To Make a Calculator Program in Python 3</a>&quot; without introducing OO concepts at all.</p>

CC BY-SA 4.0
2020-12-31T11:51:46.610Z
car/vehicle, animal/dog are not only poor, they are fatally flawed. In teaching OO, you are not, fundamentally, teaching inheritance. I'll try to come up with something to suggest.
Buffy
CC BY-SA 4.0
2020-12-31T19:30:10.937Z
Real practical example should be just that : real code from libraries or apps used in practice. For python look at popular libraries code such as numpy. Don’t do animals. Pull a hierarchy such as dataframe/series from pandas for instance.
Aksakal almost surely binary
CC BY-SA 4.0
2021-03-02T11:49:35.003Z
School, Student, Teacher, Course, Assignment
Luke Sawczak
CC BY-SA 4.0
2022-01-07T12:18:58.837Z
If you do show them the article Python, you should mention that it's quite dated (in the sense that modern Java does almost every one of those things), but that the article is still worthwhile because of its super clear explanations of a number of programming concepts, and to illustrate that different languages really do have meaningful differences.  (Again, this list of specific differences is now dated, but that if we polled the languages today, there would be other differences now.)
Ben I.
CC BY-SA 4.0
2022-01-07T12:23:05.193Z
I know! The article was published in 2006 and I can't find a modern version of that.
Qiulang 邱朗
CC BY-SA 4.0
2023-09-17T10:21:54.797Z
I find this question has some good answers too [Interesting Programming Exercises to Teach Inheritance?](https://cseducators.stackexchange.com/questions/4689/interesting-programming-exercises-to-teach-inheritance)
Qiulang 邱朗
<lesson-ideas><curriculum-design><secondary-education><object-oriented-paradigm>
Some real practical example to teach object-oriented concepts and programming (in python)
# Some real practical example to teach object-oriented concepts and programming (in python)

(Asked by: username_0 on 2020-12-31)

I have taught my high school students to write some simple python scripts, taking some ideas from ["Automate the Boring Stuff with Python"](https://automatetheboringstuff.com/), e.g. changing file names in a folder to a specific naming pattern.

My next goal is to teach them object-oriented concepts and if possible give them some "real" examples to try themselves. But most of the materials I find (most of google's top search results) about OO programming (not just python) are laden with poor examples, if I may say so. I really don't like to use car/vehicle or animal/dog to teach them the OO concept and OOP.

A. it is boring (you know high-school kids)  
B. it has no real use.  
C. as one comment said "they are fatally flawed." (But if you really like to use the animal example, check this ["Object-Oriented Design"](https://softwareengineering.stackexchange.com/questions/205459/object-oriented-design))

I plan to use [pathlib](https://docs.python.org/3/library/pathlib.html) (btw, they already have a basic idea of the difference between Windows and UNIX)

[![pathlib](https://i.sstatic.net/jvahy.png)](https://i.sstatic.net/jvahy.png)

GUI development could be another good example to teach OOP but I don't want to teach them GUI yet.

Any suggestion to introduce OO with the "real" example?

BTW, I’m not a strong advocate of object-oriented programming. But the `pathlib.Path` class is a useful abstraction especially compared with os.path, although the high school students are unlikely to appreciate that.

---- update ----

I find the python logging module is another good example, but it seems too complicated for non-experienced programmers.

When using the logging module we mainly use 3 objects, **Logger, Handler, Formatter**. Logger is the **facade**, as <https://docs.python.org/3/howto/logging.html#loggers> said,

> Logger objects have a threefold job. First, they expose several methods to application code so that applications can log messages at runtime. Second, logger objects determine which log messages to act upon based upon severity (the default filtering facility) or filter objects. Third, logger objects pass along relevant log messages to all interested log handlers.

Handler is a good example to use **inheritance** <https://docs.python.org/3/howto/logging.html#useful-handlers> and handlers use formatters, which hide the complexity of LogRecord, to the format log message.

In addition to these classes, there are a number of [module-level functions](https://docs.python.org/3/library/logging.html#module-level-functions) for convenient use.

Overall it is a good example of using **composition** and aggregation.

But I am not an expert on the python logging module, I hope someone who is familiar with the python logging module may add an answer to my question.

--- update 2 ----

I found Alan Kay answered the question [“What are the five features of the object-oriented paradigm that you consider to be important for good software engineering practice?](https://qr.ae/pNDvTp)” with these words, in my opinion, resonate with the answer username_1 gave. But how to convey these ideas to high school students or non-experienced programmers is another challenge,

> a “part” construct that can protect it's inside from its outside, and
> vice versa
>
> a “communications” construct that can convey interactions and deal
> with dependencies
>
> a “system” construct that is a combination of parts and communications
> that can fit in a part recursively, and everything is made this way
>
> the “messages” that are communicated are also in terms of the systems
>
> the system that is being made is made with the same kinds of system
> ...

--- update 3 ---

The recent log4j security flaw made me come back to my own although my question has nothing to do with log4j. I know python logging module is [adopted from Log4j](https://realpython.com/python-logging/), so I think this can be used as a good example to how different programming languages borrow the idea from each other. If the students have some knowledge about java, I may consider to introduce them this old article "[Python isn't just Java without the compile](https://bitworking.org/news/2006/08/python_isnt_java_without_the_compile/)"

BTW, username_1 gave answer about calculator as an example to practice OO, but I will argue it will depends on how you design the question and the project, e.g. here "[How To Make a Calculator Program in Python 3](https://www.digitalocean.com/community/tutorials/how-to-make-a-calculator-program-in-python-3)" without introducing OO concepts at all.

**Tags:** lesson-ideas, curriculum-design, secondary-education, object-oriented-paradigm

> **Comments:**
> **username_1**: car/vehicle, animal/dog are not only poor, they are fatally flawed. In teaching OO, you are not, fundamentally, teaching inheritance. I'll try to come up with something to suggest.  
> **username_2**: Real practical example should be just that : real code from libraries or apps used in practice. For python look at popular libraries code such as numpy. Don’t do animals. Pull a hierarchy such as dataframe/series from pandas for instance.  
> **username_3**: School, Student, Teacher, Course, Assignment  
> **username_4**: If you do show them the article Python, you should mention that it's quite dated (in the sense that modern Java does almost every one of those things), but that the article is still worthwhile because of its super clear explanations of a number of programming concepts, and to illustrate that different languages really do have meaningful differences.  (Again, this list of specific differences is now dated, but that if we polled the languages today, there would be other differences now.)  
> **username_0**: I know! The article was published in 2006 and I can't find a modern version of that.  
> **username_0**: I find this question has some good answers too [Interesting Programming Exercises to Teach Inheritance?](https://cseducators.stackexchange.com/questions/4689/interesting-programming-exercises-to-teach-inheritance)  

---

## 4 answers

### Answer by username_1 on 2020-12-31. Score: 5

I expect to update this a few times and hope to eventually have a long answer.

But let me start by explaining some things that you may already be aware of, but other readers may not.

First, OO programming is not, fundamentally, about inheritance and too many books and authors fail to understand that. Moreover, they use inheritance in a dreadful way that makes software hard to understand and harder to maintain.

For example, note that the Linnaeus style hierarchy of the biological world is almost entirely one of "interfaces" and not even "abstract classes", much less concrete classes. There are no instantiated "mammals", for example. It is only at the leave of the hierarchy that things actually exist, other than as ideas. There is some genetic continuity, of course.

Second, there are some principles that can guide you in writing and teaching OO design, but they require discipline. And part of that discipline is to control the situations in which you "break" the rules.

My first advice for anyone wanting to be an OO programmer is not to think in terms of inheritance, but, rather, of composition. Complex things (objects) are *composed* of other things (objects) that are a bit simpler than the containing object and provide it some essential service. If you write classes where all (or even most) of your instance variables are language primitives, then you don't really get it. And if those instance variables (objects or primitive) have a lot of getters and setters, then you aren't doing OO Programming at all.

In fact, making the above mistakes, requires that the programmer keep track of all details at all points of the program where OO is designed to capture decisions so that they needn't be "checked" again. Set it and forget it, so to speak.

So, if you want to build an automobile, don't think of it as a subclass of vehicle (which gains you nothing: a personal drone and a battleship are both vehicles). Think of it instead of being composed of various parts: engine, transmission, controls, accommodations, etc. And those parts are, themselves, composed of parts. An engine *has* igniters and pistons, exhaust, etc. Many of those are composed of parts also. It is only at the lowest, simplest level that you build with primitives.

Two of the principles that are worth keeping in mind and following almost always are the [Liskov Substitution Principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) and the [Law of Demeter](https://en.wikipedia.org/wiki/Law_of_Demeter).

The first suggests that if you extend a class with a subclass you don't also extend the public interface of the subclass. Then all subclass objects are substitutable, differing in behavior but not in interface. Demeter, on the other hand, forces you to write more explicit code that makes relationships clear to a reader. Of course it also forces you to introduce more names, and if they are *intention revealing names* then your code is clearer.

The Liskov principle, of course is one of the elements of [SOLID](https://en.wikipedia.org/wiki/SOLID) which you also need to incorporate into your thinking.

In my own programming I'm very faithful to Liskov, also defining Interfaces for most things before I write classes. I'm less faithful to Demeter in the heat of battle, cascading messages. But then I sometimes also need to unravel those a.b.c.d sorts of cascades to figure out what I really mean.

One goal I have in writing OO code is to seek to write only very short methods with a minimum of structure. In other words I try to minimize [Cyclomatic Complexity](https://en.wikipedia.org/wiki/Cyclomatic_complexity). My palms start to get itchy after the fourth statement in a method or if the complexity level reaches three. I can't always get away with that, but it is a goal. The solution is to refactor complexity mercilessly. Factor out methods, of course, but also "parts", creating new classes to manage the complexity. Even if many of those classes are Singletons the code is usually improved and having the goal in mind from the start, means that the refactoring step is less needed.

Design patterns are tools that you need to be an effective programmer in most OO languages. Especially helpful ones are Strategy, Decorator, Observer, and Iterator. Most of these are actually used to build the various Java libraries.

---

Now, to get to the actual question asked here. But note that a lot of learning can take place even if the students never reach completion of the project in the allotted time. An agile approach (Extreme Programming, say, with you as "Customer") to development leaves them with *some* functionality even if not all specifications are implemented.

### Dungeon Game

Build a text based dungeon game. The main objects are characters (people), places, and things. The places are organized in some sort of map, maze, or grid. Things happen when characters enter places. Characters find and carry things. The things have actions, depending on the kind of thing. A "spell" is a "thing" whose action might depend on context. A "transporter" object might work differently in different rooms (strategy objects).

Note that the classic board game [Chutes (or Snakes) and Ladders](https://en.wikipedia.org/wiki/Snakes_and_ladders) is a simplified version of this. A text based version avoids a lot of complexity.

### Calculator

A calculator has parts such as keys and the display. Less visible are the internal memory, possibly a stack. Even the operations can be objects. The behavior of the keys changes, depending on the state of the computation (Strategy pattern). It is possible to build a simple calculator without a single IF statement, actually.

### Abstract Computer with an Assembly language

A Stack Based computer processor simulation is pretty straightforward. There may be accumulators and such, but a single stack on which all operations are done is simple and complete. The operations can be objects (parts). One advantage of this example is that most of the necessary methods can be very short. A program can be read with a Java Scanner object. It needs a program counter at least and possibly a frame pointer if the language is to support subroutines.

### Sticky Notes (I haven't tried this)

An application that lets users keep notes and cross reference and organize them. Some classes might be Notes, Keywords, Connections, Lists.

### Jeopardy

A simulator for the jeopardy game from TV. Categories, Answers, Questions, Teams, Scores.

(Back soon, maybe).

> **Comments:**
> **username_0**: I have been struggling to a find a way teach OO because I have my doubt. Check my question here https://softwareengineering.stackexchange.com/questions/419122/does-oop-overemphasize-the-importance-of-noun-and-thus-put-action-verb-in-the-le  
> **username_0**: I am quite familiar with http://todomvc.com/ I probably can adapt it to my teaching.  
> **username_1**: There are links to and explanations and examples of MVC (in Java) here: http://csis.pace.edu/~bergin. Sadly, the applet version no longer runs on the web.  
> **username_0**: todomvc is not really about mvc but the the choices and the comparison of different web technologies to implement a todo list. I mentioned because you mentioned Sticky Notes.  
> **username_0**: I found an interesting answer Alan Kay gave and updated my question again.  

---

### Answer by username_5 on 2021-02-05. Score: 1

I found a Python class to be so simple to write (for "mundane" tasks), that they can grow naturally out of a desire to simplify and refactor code in development. It is very much a *pragmatic* bottom-up approach; you were expecting to hack some simple code for a particular purpose, then it grows a bit and you find you have several functions handling "structures" that were tuples or arrays or even globals. Suddenly, you see the light and create a class, and the code size gets divided by 2 or more, and is *so much simpler*.

This is an easy way to argue for OOP, by taking some "flat" concrete existing code and looking for the abstraction that could be made, moving the data out of the function parameters, into the class, and using `self`.

Things like inheritance can similarly be discovered almost naturally; you use an existing class that doesn't quite do what you want and you need to change it; instead of copying and modifying it, you subclass and change or add a method.

For concrete examples, you can look at computer hardware itself. At a low level, registers are often partitioned into several disparate functions. If you want to set a feature bit to 1, you need to shift it left 20 bits, read the current value of the register, mask out bits 0 to 5 as they are "write 1 to clear", and so on. Try emulating a serial port 16550 uart; it is good for the soul. And, of course, if you use MicroPython running on a real microprocessor, you could probably even try out your code.


---

### Answer by username_6 on 2021-06-02. Score: -1

My go-to example for both data modeling and OOP (which in both cases revolve around a kind of normalization), is a **video rental store**. It's maybe a very dated example, feel free to change it to a library or a rental store for other things, but I find that the video store example both highlights the intricacies of OOP and data normalization, while at the same time being a very simple context to grasp.

The main goal is to build up to a three table/class diagram: `Customer`, `Video` and `Rental` (which is the cross table between customers and videos).

The rest of this answer is just tips on how to relate specific OOP basics to the example at hand.

---

**Why objects?**

Well, how would you store your video data, if you want to track three things for a rental: the customer name, address, video name, and expected date of return.

Ask the students to write a very simple program that is able to tell you that Alice rented Antz, Bob rented Bee Movie, and Charlie rented Cars. Let them rely on some reusable `PrintRentalInfo` method, but allow them to define the method parameters as they see fit.

Students who haven't yet seen OOP will use four distinct arrays and rely on the fact that one video is found on the same index in all four arrays. Explain to them that instead of having a "bag" of customer names, a "bag" of addresses, a "bag" of video names, and a "bag" of return dates is not really easy to work with. Suggest the idea that instead of making a "bag" per data field, it would make more sense if we made a "bag" per rental.

Build the `Rental` class with the four properties. Build the same application as they did, but using OOP. This will show them object initialization, how different objects have the same structure but individually unique content, and how you can pass an object around (as opposed to multiple method parameters of primitive types).

Really highlight how easy it is that you can move this rental "bag" around from method to method, keeping all relevant information together.

---

**Why more than one class?**

A fourth customer appears. Her name is also Alice. You run into an issue here, because now you're unable to tell *which* Alice has rented which videos, and you don't want to fine the wrong Alice.

Also, the original Alice has called us to let us know her address has changed. Point out the difficulty of having to go through all the rentals and figuring out that you can't just blindly change "old\_address" to "new\_address", because there may be other customers living on that same address who did not move with Alice. Also, you can't rely on the name either, as the fourth Alice has already made some rentals too.

*If the students keep protesting that you could do it based on the combination of name and address, as what happens if those two Alices live on the same address, and only one of them moves.*

Suggest to the students that it would make a lot of sense if we had a separate list of all our customers and their addresses, so we could tell them apart by more than just their name, and easily change one person's details.

Goal: build a `Customer` class, and change `Rental` so it includes a `Customer` property as opposed to name/address properties.

Focus: very much highlight how you can have two **different** customer objects, even when their names and addresses are the same.

Extra: You can take the same approach to creating the `Video` class, so you can track the specific videos you have. Maybe leave this as an exercise to the students, as this is much of the same as before.

---

From this point on, you can expand the business logic based on what you want to showcase.

* **Inheritance** - Maybe the store rents `Video` and `Game`, but you still want `Rental` to be able to link to either of them (using the base `RentableObject` class)
* **Interface** - You can use the same example as inheritance.
* **Data normalization** - How would we go about both tracking the movies we have available, and the individual physical cassettes (we could have multiple of the same movie)? How would be be able to track fines that a customer has incurred, and which of them they have already paid?
* **Data transformation** - Our boss wants us to print a weekly report on all rentals made, rentals returned, incurred fines, and fines from before which *still* haven't been paid.
* **Reference vs value** - Add a `Price` to both the `Video` and `Rental`. Showcase how you set `rental.Price` based on `video.Price`, but when `video.Price` later changes, `rental.Price` is untouched. Now repeat the same exercise with a reference object (e.g. changing the customer's name).

I find that the context for this example is very easy to grasp, and has a lot of opportunity for expansion. This could grow into a long-term project that you keep expanding, which can be a valuable lesson if you want to teach your students about how to handle changing requirements and the benefits of clean coding, or maintenance and legacy development.

> **Comments:**
> **username_0**: Thanks for the ideas! Some suggestions, a.  I use python so I believe we will first use dictionary not array to build the first version b. this is a good example to introduce 'id' concept, id for customer, id for video.  
> **username_6**: @Qiulang: Absolutely. While this does muddy the line a bit between OOP and data normalization, these two concepts are thematically linked and often feed into each other in actual business projects, so I very much like that you learn a bit of both at the same time.  
> **username_7**: A video store is a nice example of an object-oriented design. But how do you use it? Are you going to keep an array of customers, and at random times they visit the store? What are those times? How do you make this realistic? That driver program may actually be harder to program than the classes. And how do you determine that your whole program does what it's supposed to do?  
> **username_6**: @VictorEijkhout: I'm not quite sure what you're focusing on here. The answer is focused on an example that drives the design of a video rental application, not a simulation of how it will be used during a real day. How to realistically simulate usage in a specific scenario is a completely different topic and not at all something OOP-learners should be concerned by. Part of this exercise is to let the students find a solution and then showcasing betters ways of doing the same thing; which precludes giving a pre-formatted input as this would start revealing the intended design.  
> **username_6**: @VictorEijkhout: Your last question implies you're bring up TDD (or some kind of testing at least). While I appreciate the value of TDD (and testing in general), the first introduction to OOP is not the right time to also introduce testing, nor should the two be merged into a single practical exercise for the students.  
> **username_7**: @username_6 I wouldn't go as far as doing TDD or Unit Testing, but I'm sticking to my point that if you assign a project, you should outline not only the design but some usage scenarios. I don't know if you're an active teacher, but it's my experience that students will happily do insufficient "testing" whether their code is actually sensible.  
> **username_6**: @VictorEijkhout: You're thinking of a much bigger exercise than what I am describing here. The only part where I suggested that students try it themselves (before showing them how OOP can do it better) would take around an hour (maybe two) to complete. Everything after that is described as the teacher working through the OOP implementation, not the students. It's of course a good idea to also give students some exercises themselves but I never claimed that my answer contains a complete curriculum; just a practical example that easily highlights what OOP can be leveraged for.  
> **username_6**: @VictorEijkhout: The focus in this answer is also not on UI or end-user interaction, but rather how to model the internal workings of the application (specifically its data structure) based on a straightforward use case. The use case is very intentionally chosen to be both trivial to understand (person rents thing), and easy to adjust its complexity to gradually introduce extra requirements which highlight more advanced OOP principles (examples provided in the answer at the end). If you want to review and test every student's work, by all means; but that is simply not what this focuses on.  

---

### Answer by username_8 on 2021-01-01. Score: -2

How about a boring\*, but realistic, commercial example? When the students leave the "hallowed halls" and become entrepreneurs in start-ups, they will be faced with the relationships between Customer, Product, and Sale (Transaction).

By keeping all of the Product data (for example) 'together', we introduce the advantage of encapsulation over a basic data structure, eg array. There is scope for hierarchies (later).

Per earlier "composition" responses, when we look at an Address we see that each Customer must have one, oh wait, more than one if his/her billing address is distinct from the delivery address. So, if an Address is part of a Customer, should Customer "inherit" from Address? ("is a" cf "has a"!) What about the difference between a personal customer and a corporate?

Do both have a name, and address, ...? How are they similar/where do they differ? How do we keep track of the individual from the Corporation with whom we are dealing?

What happens when we make a sale? Is this data to be part of the purchasing-Customer's object, or the Product object - or objects, or what? Thus, "Interfaces" (in some languages), an invitation to expand the SRP into micro-services, drop into APIs...

There's plenty of scope for SOLID principles, best practices, language differences, and all-the-fun-of-the-fair. Meantime, you could 'dress up' problems to make the toy-examples seem 'real' any-which-way; and the students are learning 'how the world works' and thus (hopefully) enthused to progress.

* personal opinion: can't imagine how Pathlib avoids the "boring" criterion (besides it has its own struggles with 'the concrete', given its abstraction from the OpSys - which is already an abstraction ... Alice, rabbit hole, Toto != Kansas...)

> **Comments:**
> **username_1**: Actually, no, a customer is not a subclass of address. That makes no sense. If it makes no sense then the software is conceptually broken and can't be maintained. One of the worst ideas ever to appear in an elementary book was to make Cylinder a subclass of Circle, just because the Circle class already had some fields that a Cylinder also needs.  
> **username_0**: path is something they know and they notice the difference between windows and unix. Teaching pathlib really teaching something they can learn, think, explore. So it is not boring (my opinion).  
> **username_8**: Apologies @username_1, it may not have been apparent that I use a Socratic approach towards trainees' learning. You and I both know about sub-classing and composition!  
> **username_6**: @username_1: The inheritance idea was phrased as a question for the teacher to explore with the students. Not as the right answer. Exploring bad ideas that most (if not all) developers intuitively think of before they understand why it's a bad idea, is a really good and pro-active way to help your students get ahead of the curve as opposed to knowingly and unguidedly letting them fall into the trap.  

---

