Know about design patterns for interviews.
10,000ft viewpoint ones, maybe. But, there are useful design patterns that aren't like that, such as the observer pattern, which you are likely to implement poorly and incompletely, when not considering it
(shades of Greenspun's tenth rule?); but that you can implement pervasively, in ways that improve your code and design process, if you recognize early on that you're halfway to using it. Because, at that point, you can go check out mountains of both academic and commercial research, and real-world use cases, where people have already made, and corrected, mistakes in using it, and also found ways you didn't think of to extend it.
Memorizing lists of them will do no good, and don't worry about the hair-splitting details between some, but try to
familiarize yourself with them, in general, so that you won't get trapped trying to hack your way around fixable problems you didn't even quite realize you were creating. The apparently simple 'right way' to do some patterns has often been arrived at by people smarter, more creative, and more experienced than you or I, spending thousands of hours trying to figure it out in the context of actual programs, only much later for someone else to look at the result, make a diagram of it, give it a name, and make it look easy

.
When somebody checksIn, it is no longer a reservation, it becomes a CheckIn. On the day of checkOut, CheckIn becomes a checkOut. Then, it would become a completed and paid reservation.Reservation->CheckIn->CheckOut->CompletedHotelBooking. Is that inheritance?
Yes, though it's generally not used that way
(a Reservation would just have a field added for its current stage, since making new derived objects gets expensive, cumbersome, and harder to document as it becomes more pervasive). Inheritance is the taking of the properties of one class to derive another
(common OOP languages don't do multiple inheritance, some do as a series of single inheritances, while some allow arbitrary multiple inheritance, allowing true union types). You generally don't want to do that just to represent a change of state, because, really, an object exists primary to store a certain kind of state (as defined by its class). Each one should have all the info of all its predecessors, so it would be just as well to have all the fields in one class, with the ability to get the current stage in the process, and have unset fields as null or other special values. Separating them could be done just as well by placing them in different collections, where appropriate. You're doing the technique right, but that would beg for spaghetti code and unnecessary complexity over time in a real application, compared to making the base reservation class a bit more robust.
A more canonical example: let's say, for instance, you make a Person class, which stores and ID and name (since name might not be unique). It has setters and getters. Everyone in the world, and some business entities, are Persons.
Now then, you want special properties for hotel staff, so you make Staffmember from Person, adding a job title and hours. Staffmember
inherits Person. It is now a subtype of Person. Anything that can use a Person can also use a Staffmember.
Well, you then want a customer to be distinct from any hotel staff, so you make a Customer from Person, too. Dunno what else you'd add, but still, it's a Person for parts that need a Person, where anything dealing with extra info for a Customer would only allow Customer subtypes*.
The usefulness of this, when applied well, is that any container that has a Person can also have a Customer or Staffmember. Consider:
Code:
Person as {
ID as unqiue_ID
name as string
}
Reservation as {
day_for as date
day_reserved_on as date
room_reserved as room
reserved_for as Person
reserved_by as Person
}
Now setting the room as reserved by a staff member for a staff member, where staff members are actually objects of their own class, will work just fine, since a staff member is a subcategory of a person, in the system, and thus should have any and all properties of a Person, as well as additional properties related to being workers for the hotel.
As well, other classes and functions that just want a Person will have no access to additional customer or business-related information, even though you are storing it in the same actual structure in memory.
As a note, not all OOP languages allow subtyping via inheritance, though languages that don't are not often used, because that's one of the more handy features of OOP.
1)Would I store these entities in the same csv file with an additional Boolean element. So reservation would be TFFF->FTFF->FFTF->FFFT.
Sorry guys, must be driving you crazy with this.
You can, but...if you're going to do that, why not have a byte or enum in Reservation, then store it out as a number, as well? Say, 0 means something is wrong (exception, just in case), 1 is a made reservation, 2 is a checked in, 3 is checked out, 4 is done. Or, you could even make the CSV descriptive, parsing words back in and matching them to the numbers, which would allow the internal implementation to be more decoupled
(no point in wasting the space of storing and working on strings in the system, for such basic work).
Customer object has customer data, make it responsible for CRUD customers.
Alternatively, make it just store and access a customer's data, with a separate class for actually handling the CRUD portion for the whole set of data. Either way works. The latter adds to modularity, but since that kind of modularity tends not to be re-used, since it's likely coupled to Customer-specific info, it's more a matter of preference in style and thought process
(note: re-use is one of those things that is simply not paradigm-dependent, either; OOP, functional, straight imperative, even procedural...as long as you can name entry and exit points, you can re-use code, if it is made to handle a general enough case).
2) Are these correct assumptions?
Maybe? I'd say they're a little too vague to be certain, still. Definitely on the right track, though.
3) Define the responsibilities of the system and then work out the best way to achieve this. e.g Maintain room bookings. the Calendar class. Each time a reservation is made, the reservation class will notify the calendar class of certain date and tell it room type e.g if Single Rooms>0 then SingleRooms-1.
Yes. Also, while they are always bad ways to do it, stick to one viewpoint for a certain aspect of the program. Data organization, data flow, observer/messaging, and other patterns are often equally viable
(it's handy to know some, to recognize when you're half-assed doing one, and doing it right is well-documented, or doing on that's wrong for your task), but at some point, what really matters is deciding one aspect of the design, like decision-making (responsibility-driven), interface, data storage/persistence, etc. is extremely important, and making that aspect's needs a conceptual framework, where the rest of the program must make sense in its context
(making code that someone else can easily internalize the workings of should often be equally, if not more, important, than caring about the computer executing it). That the same narrow design idea hardly ever works well for both front ends and back ends of real applications, leading to needing some reconciliation between each other, is part of how many design patterns (like the pervasive MVC) come to emerge.
Make reservation, Get reservation and CancelReserve, these are similar operations, so could you put these in an interface class?
P.S. I happened to think about this after getting some coffee. Forget, for a moment, that languages support explicit interface types of classes. That's an implementation detail that is language-specific, and usually an ad-hoc way of adding features they either didn't think were needed at first, or weren't sure how to add without breaking rules they wanted to keep coherent.
One of the more realistic benefits of OOP
(though the same can usually be done in functional languages, w/o objects, as well, and some imperative non-OO languages, but almost all OO languages are made with this in mind), over other paradigms, for practical long-lived applications is that
you don't need to care. That's what encapsulating values and sub-objects behind setters and getters
really gets you. The ability to care about the higher-level aspects, without being overly concerned about the lower-level aspects in the process, until you need to optimize certain code.
Why does that matter? Let's say that you have a collection of objects being accessed by these functions, and each object is a complete reservation object. Now, your program is live, making some money, and you're needing more performance in doing simple operations on reservations, after reaching millions of them in the system, or you need to search through those millions quicker, and are finding that faster computers aren't able to do it well enough. They've hit a capacity wall. So, you profile it with random data similar to the customer(s)'s in question, and find that those reservation objects are eating up a ton of time, but the CPU is mostly stalled. So you investigate more, and find that your collection, and the objects, have too much overhead and indirection, causing bad results from prefetchers, and a cache footprint far larger than the data size.
So, you need to make each reservation smaller in memory, make searching through many of them easier, and make each lookup a better fit to HW speculation (binary searches over a flat-ish binary tree, skip-lists, reduce call depths of complex container objects, etc.). Now, there are quite a few ways to do this, the best varying by other variables, including time available, library options, latency requirements, and so on. The best way could be to hide it all behind views in a local database. It could be to make it a simple tree of radix-order-ordered (list of 1xx, then 2xx, then 4xx, etc.) lists/arrays, for quick access and searching. It could be best/easiest to have simple in-memory structures, an optimized file format, and SSDs to store it.
The nice thing about a class with those setters and getters, and other methods to hide access to the actual data, is that you can make a new version of your program, with the optimized reservation storage and search system, and only need to make a handful of changes outside of that system itself, because >90% of the code only cares that the methods of the object(s), sent the right arguments, will return the expected results. Without that kind of encapsulation, you have to either be extremely rigid in defining abstractions
(I mean, the same thing can be done in C, but C does not exactly encourage it, or make it easy to read and write), or be paranoid as all hell when about minor structure-related side-effects, when having to update the rest of the application that relies on reservation's old behaviors not changing.
The class defines an interface, so you can add a layer behind that, if needed or desired, that is much more than the basic set, get, add, remove, filter, etc., that appears to waste more space than anything else.
http://en.wikipedia.org/wiki/Program_optimization#Quotes
I'm a big fan of eager evaluating functional languages for general use, but if there's one
huge benefit that imperative OOP has, over other viable business-world options, it's being able to dig in and optimize when necessary, but leave it well enough along when that's not needed, even when you're dealing with weird code that's been written by 50 people over the least 10-20 years.
Perhaps somebody at my level shouldn't read that.
You might not understand it all, yet, but basically, don't drink the Kool-aid. Procedural sucks
(for any kind of higher-level thought, it really does; but somehow stable systems keep getting made in them), imperative sucks
(too many chances to shoot yourself in the foot; but you know, computers kind of exist to manipulate state, and algorithms are never written as state-free function definitions), functional sucks
(computers do state, not expression evaluation; but compare bugs per programmer-hour), OO sucks
(how much space in this thread has been showing its limitations...yet, something that wide user base can make decent use of matters more than perfection within a narrow domain, and OOP is sufficiently versatile), and so on.
Our tools shape our thoughts as more than we'd like, so learning more is always a good thing**. But, there has yet to be a programming paradigm or specific language that can do everything really well
(even the outstanding languages make huge trade-offs between code for humans to use, and performance on a computer), and at least half of the supposed benefits of any given paradigm are leaps of faith
(strictly procedural to any decent structured programming probably being the one paradigm difference that lacks the need for faith). At the end of day, each good language is like a different brand and model of multitool.
* Also, to see why relational is the bees knees for this, consider what you'd do when you need a staff member to b a customer in another hotel...relational has ways to deal with it that can be implemented almost identically across non-relational DBMSes (Person table, Customer table with Person.ID as FK/PK, Staff table with Person.ID as FK/PK, handle compatibility issues in views), where the logically necessary decision is language-dependent for OO. The dirty secret of DBMSes, too, is that you can hide both occasional relational model obtuseness, and SQL implementation inadequacies, in triggers and sprocs, so it looks all clean and simple from the outside
.
** on that note, after you get a better handle on OOP, if you haven't already, go learn a LISP.