Skip to content

Commit a33ff0d

Browse files
Added HelloApartment
A commented example of simple OOP paradigms such as abstraction and encapsulation. Meant to illustrate some of the benefits of OOP over functional programming.
1 parent 0340119 commit a33ff0d

File tree

6 files changed

+259
-0
lines changed

6 files changed

+259
-0
lines changed
2.01 KB
Binary file not shown.

HelloApartment/HelloApartment.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import java.util.*;
2+
3+
public class HelloApartment{
4+
5+
public static void main(String []args){
6+
System.out.println("Hello World");
7+
8+
// Test the Room and Owner classes
9+
Room myRoom = new Room();
10+
System.out.println("Owner is currently: "+myRoom.getOwner());
11+
myRoom.setOwner(new Owner());
12+
System.out.println("Owner is currently: "+myRoom.getOwner());
13+
myRoom.getOwner().setName("John Doe");
14+
myRoom.getOwner().setPhone("2125551234");
15+
System.out.println("Owner is currently: "+myRoom.getOwner());
16+
17+
// Release myRoom for garbage collection
18+
// I'm used to manual memory management from C++, so not entirely necessary for Java
19+
myRoom = null;
20+
21+
// Now, create an "apartment." This could be its own class, but for the sake
22+
// of simplicity, let's just use an ArrayList.
23+
ArrayList<Room> apartment = new ArrayList<>();
24+
25+
int numberOfRooms = 15;
26+
Owner management = new Owner("Management",new Double(5550000000L));
27+
for(int iter = 0; iter<numberOfRooms; iter++){
28+
// Let's randomly assign "rooms" (min. 2'x2') to management, or John Doe
29+
if(Math.random()>0.5){
30+
// Make room sizes incremental, so we can distinguish them
31+
apartment.add(new Room(7*iter+2, 3*iter+2, management));
32+
}else{
33+
// Create a random phone number from 1000000000-99999999999
34+
double randomPhone = Math.random()*(double)8999999999L + (double)1000000000L;
35+
apartment.add(new Room(10*iter+2, 5*iter+2, new Owner("John Doe "+iter,randomPhone)));
36+
}
37+
}
38+
39+
// Now let's find the total square footage of the "apartment",
40+
// and since we're already iterating over the ArrayList, let's
41+
// print out some details for each room to double check
42+
double totalSqFt = 0;
43+
for(Room room : apartment){
44+
System.out.println("Room : "+room);
45+
totalSqFt += room.getLength()*room.getWidth();
46+
}
47+
// Note that rooms owned by the management will all reference the same Owner
48+
// object - the "Management" Owner object. Therefore, changes made to the
49+
// object will show up for all of the Rooms. This allows for an amazing
50+
// amount of flexibility when compared to functional programming. Instead of
51+
// trying to keep track of which array index corresponds to which array index
52+
// and what the value of the element at that index corresponds to in another
53+
// array, etc... You just reference the actual object, and any changes you make
54+
// are immediately avaliable and intuitively accessible to every programmer
55+
// working on the project.
56+
System.out.println("Total Square Footage for Apartment: "+totalSqFt);
57+
58+
}
59+
}

HelloApartment/Owner.class

1.46 KB
Binary file not shown.

HelloApartment/Owner.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
public class Owner{
2+
// Why decouple something as simple as a room's "owner" into its own class?
3+
//
4+
// You don't need to - a string might be fine. But if you foresee a need for
5+
// more complicated bookkeeping in the future (e.g. owners might need to be
6+
// referenced for other things, such as a homeowners assn. board position, or
7+
// you might want to keep track of one person's entire real estate portfolio
8+
// or something), it might be beneficial to create a new class for "owners"
9+
// and reference them elsewhere.
10+
// The added benefit is that you just added a layer of abstraction for your
11+
// own benefit: You no longer have to remember how you kept track of the
12+
// owners, or what data structure you used to store their names, phone
13+
// numbers, etc. That is now all hidden behind a layer of abstraction by
14+
// simply having created this class. Something as unintuitive as
15+
// //Mental note: John Doe's location in the owners array is 5
16+
// //Mental note: Contact information is stored in the 4th position
17+
// // of the owner array... or was it 3?
18+
// //Mental note: Contact information went... address, phone number,
19+
// // email, then work phone. No, it went phone number,
20+
// // address....
21+
// System.out.println(owners[5][3][0]);
22+
// can instead become the much more intuitive, much clearer, object oriented
23+
// version:
24+
// // contactManager is a class that handles the owner "database"
25+
// // getByName is a method of contactManager that returns
26+
// // the corresponding Owner object
27+
// // IntelliSense should automatically include getByName
28+
// someOwner = contactManager.getByName("John Doe");
29+
// // getPhoneNumber is a method of Owner that returns a phone number
30+
// // IntelliSense should automatically include getPhoneNumber
31+
// someOwner.getPhoneNumber();
32+
// and for the most part, you won't need to recall the inner workings of the
33+
// class. You have essentially created a black box, and you can use that
34+
// with the assumption that .getName() will give you a String, regardless of
35+
// how you decide to store names down the line, and that .getPhoneNumber()
36+
// might give you an String, regardless of how you might store phone numbers
37+
// down the line.
38+
39+
private String name;
40+
private Double phone;
41+
42+
public Owner(){
43+
this("No Owner", (Double)null);
44+
}
45+
public Owner(String name){
46+
this(name, (Double)null);
47+
}
48+
public Owner(String name, double phone){
49+
this(name, new Double(phone));
50+
}
51+
public Owner(String name, String phone){
52+
this(name, Double.valueOf(phone));
53+
}
54+
public Owner(String name, Double phone){
55+
this.name = name;
56+
this.phone = phone;
57+
}
58+
59+
60+
public String getName(){
61+
return name;
62+
}
63+
public void setName(String newName){
64+
name = newName;
65+
}
66+
public String getPhone(){
67+
if(phone!=null){
68+
return String.format("%4.0f",phone);
69+
}else{
70+
return "Unknown";
71+
}
72+
}
73+
public void setPhone(String newPhone){
74+
// Here, you'd do validation and sanitization, but I won't
75+
phone = Double.valueOf(newPhone);
76+
}
77+
public void clearPhone(){
78+
phone = null;
79+
}
80+
81+
// For debugging purposes, let's override the standard Object.toString() method
82+
// that is called when "casting" the class to a string e.g. when you say
83+
// System.out.println("Some String: " + someClassInstance);
84+
@Override public String toString(){
85+
return "Owner ["+name+" | "+getPhone()+"]";
86+
}
87+
88+
}

HelloApartment/Room.class

1.64 KB
Binary file not shown.

HelloApartment/Room.java

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
public class Room{
2+
private Owner owner;
3+
// | | | These are all arbitrary names, and are picked solely for
4+
// | | | convenience. Good code must be maintainable, maintainable
5+
// | | | code should make sense. Calling this
6+
// | | | private Human who;
7+
// | | | would make no difference for the machine, but it would for me.
8+
// | | In C++, this would be a pointer* to the Owner object in the heap,
9+
// | | but Java runs on a Virtual Machine, so having a pointer to a location
10+
// | | in memory is unnecessary, so Java uses what they call "references",
11+
// | | which are different from C++ "references" in that
12+
// | private allows me to impose certain access restrictions on myself (more so
13+
// | than the program) or anyone else who I want using my code, so that I limit
14+
// | the points where my code can break. E.g. restricting this now drastically
15+
// | changes how I write code later. Instead of calling
16+
// | myRoom.owner = new Owner();
17+
// | elsewhere in the code, where I wouldn't normally think of looking when
18+
// | I go back for my next code update or rework that involves the Room class,
19+
// | and potentially breaking something because I later decided to change how
20+
// | I want my program to assign or remove owners, I might instead call
21+
// | myRoom.assignOwner(trustees.getChairman());
22+
// | and assume that the only code that touches the Room's owner field is
23+
// | the Room class itself.
24+
25+
private double width;
26+
private double length;
27+
28+
// Overloaded constructors - might be useful for certain applications,
29+
// but constructors with fewer arguments might introduce errors down the line
30+
// if you don't check for null references
31+
// You can also call the superclass constructor within this constructor
32+
// for further control, e.g. super(args...); instead of this(args...);
33+
public Room(){
34+
this(0, 0, null);
35+
}
36+
public Room(double width, double length){
37+
this(width, length, null);;
38+
}
39+
public Room(double width, double length, Owner owner){
40+
// The only time I'll directly assign these variables is the constructor
41+
this.width = width;
42+
this.length = length;
43+
this.owner = owner;
44+
}
45+
46+
public double getWidth(){
47+
// The benefit of having getter methods is similar to the benefits of
48+
// having setter methods. However, the most important difference is that
49+
// regardless of the method's signature (specifically, its return type),
50+
// a getter method allows the abstraction of the actual data into whatever
51+
// form we want. We could have just as easily not stored the actual width
52+
// of the room (say, if the Room itself has many Compartments) and instead
53+
// called a class method that would calculate it for us (e.g. a method
54+
// like sumCompartmentWidths() or something similar). With a getter method,
55+
// the internals of the class do not matter to anyone working WITH the class
56+
// (not working ON the class). Again, we black box the internals, and
57+
// instead present a method that is guaranteed to give an integer width.
58+
// However, for this example, we'll just return Room.width:
59+
return width;
60+
}
61+
public void setWidth(double newWidth){
62+
// The benefit of having setter methods is that you can now manipulate the
63+
// input - something that wouldn't be guaranteed if Room wasn't an object,
64+
// and its member variables weren't private. That is to say, separating
65+
// the assignment as a method (instead of setting .width, for example)
66+
// allows you to do any number of things, including
67+
// * input sanitization (e.g. trim, reencode, or cherry-pick stuff)
68+
// * input validation (e.g. throw errors if provided with bad input,
69+
// or silently substitute a valid value)
70+
// * user experience "niceties" such as log messages, warnings, etc.
71+
// * feeding the input into some other function before using it
72+
// * etc.
73+
// and allows you to do much more "under the hood" than a simple value
74+
// change. For example, let us now require our widths to be greater than
75+
// 0, but less than 100, for the sake of example, and display a warning
76+
// if the method argument is outside that range. We can then choose how
77+
// we process the input. Let us say that we wish to use the range as a
78+
// sort of threshold, and that arguments >100 fall back to 100, and
79+
// arguments <0 fall back to 0.
80+
if(newWidth<0){
81+
System.out.println("Warning: You tried to set the width of a room to <0.");
82+
System.out.println(" Assuming new width of 0.");
83+
newWidth = 0;
84+
}else if(newWidth>100){
85+
System.out.println("Warning: You tried to set the width of a room to >100.");
86+
System.out.println(" Assuming new width of 100.");
87+
newWidth = 100;
88+
}
89+
width = newWidth;
90+
}
91+
92+
public double getLength(){
93+
return length;
94+
}
95+
public void setLength(double newLength){
96+
length = newLength;
97+
}
98+
99+
public Owner getOwner(){
100+
return owner;
101+
}
102+
public void setOwner(Owner newOwner){
103+
owner = newOwner;
104+
}
105+
106+
// For debugging purposes, let's override the standard Object.toString() method
107+
// that is called when "casting" the class to a string e.g. when you say
108+
// System.out.println("Some String: " + someClassInstance);
109+
@Override public String toString(){
110+
return "Room ["+(int)width+"x"+(int)length+" | Sq.ft. "+(int)(width*length)+" | Owner: "+owner+"]";
111+
}
112+
}

0 commit comments

Comments
 (0)