Skip to content

Instantly share code, notes, and snippets.

@jacobdanovitch
Created March 4, 2018 00:43
Show Gist options
  • Save jacobdanovitch/d557f9f7ef6f3c287555a4a26c0533f6 to your computer and use it in GitHub Desktop.
Save jacobdanovitch/d557f9f7ef6f3c287555a4a26c0533f6 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Opening Our New Store"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Grand Opening"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Consider our newly opened store. We'll setup our instance variables with some basic information about a store. Note the array of Products - this is what we'll be focusing on today!\n",
"\n",
"We have a few methods here. Our toString is rather basic. We use an addProduct() that should be quite familiar to you from tutorials thus far. The last method is pretty simple; it prints out each product in the catalog. Since the catalog can have as many as 100 products, we stop printing once we hit a null value."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public class Store {\n",
" public String name;\n",
" public String address;\n",
" public Product[] catalog;\n",
" public int numProducts;\n",
" public final int MAX_PRODUCTS = 100;\n",
"\n",
" public Store(String nIn, String aIn) {\n",
" name = nIn;\n",
" address = aIn;\n",
" catalog = new Product[MAX_PRODUCTS];\n",
" numProducts = 0;\n",
" }\n",
"\n",
" public String toString() {\n",
" return name + \" located at \" + address;\n",
" }\n",
"\n",
" public void addProduct(Product p) {\n",
" if (numProducts < MAX_PRODUCTS) {\n",
" catalog[numProducts++] = p;\n",
" }\n",
" }\n",
"\n",
" public void displayCatalog() {\n",
" System.out.println(\"Catalog for \" + this + \":\\n\");\n",
"\n",
" for (int i = 0; i < catalog.length; i++) {\n",
" if (catalog[i] == null) {\n",
" break;\n",
" }\n",
" System.out.println(catalog[i]);\n",
" System.out.println();\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## What's in a Product"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As an important part of every new store, we must have products. Each product should have a name and a price, of course. It should also know the store to which it belongs (kind of like the ticket class in the current assignment). Lastly, it must know its quantity (inventory). \n",
"\n",
"Each product should also be able to be sold and be restocked, as well as have a toString() method. \n",
"\n",
"We use the word \"protected\" in our Product class as another layer of encapsulation. This tells Java that the only people who can access this variable are subclasses of the Product class.\n",
"\n",
"Note that in the constructor, we call store.addProduct(this). The keyword \"this\" is very useful. As Lanthier said, to know what \"this\" refers to ... look to the top of the class! So here, we are telling Java to take \"this\" Product object, and add it to its store's catalog automatically. This saves us a lot of work from having to do that by hand every time!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public class Product {\n",
" protected double price;\n",
" protected String name;\n",
" protected Store store;\n",
" protected int inventory;\n",
"\n",
" public Product(String nIn, double pIn, Store sIn, int iIn) {\n",
" name = nIn;\n",
" price = pIn;\n",
" store = sIn;\n",
" inventory = iIn;\n",
"\n",
" store.addProduct(this);\n",
" }\n",
"\n",
"\n",
" public String toString() {\n",
" return name + \"\\nCosts \" + price + \".\\n\" + inventory + \" remaining at \" + store;\n",
" }\n",
"\n",
" public void restock(int numberIn) {\n",
" inventory += numberIn;\n",
" }\n",
"\n",
" public void sell(int numberSold) {\n",
" inventory -= numberSold;\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Stocking Up"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's test out our Store and Product objects to start. We won't spend too long on this as it should mostly be review. We'll create two new products for our store Abstentions, and then we'll sel and restock them. Note that we never have to call abstentions.addProduct(): this is automatically done for us in our Product contructor!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Store abstentions = new Store(\"Abstentions\", \"1125 Colonel By Dr.\");\n",
"\n",
"Product p1 = new Product(\"Jam\", 3.50, abstentions, 20);\n",
"Product p2 = new Product(\"Apple\", 4.25, abstentions, 33);\n",
"\n",
"abstentions.displayCatalog();\n",
"\n",
"p1.sell(5);\n",
"p2.sell(5);\n",
"\n",
"abstentions.displayCatalog();\n",
"\n",
"p1.restock(10);\n",
"p2.restock(50);\n",
"\n",
"abstentions.displayCatalog();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Redefining Products"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We're now going to get into one of the most important ideas in Java - abstraction. Let's rewrite our project class and take a look at the differences.\n",
"\n",
"1. Why is the word \"abstract\" before public?\n",
"2. Where is the constructor!?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"abstract public class Product{\n",
" protected double price;\n",
" protected String name;\n",
" protected Store store;\n",
" protected int inventory;\n",
" protected int aisle;\n",
"\n",
" public String toString(){\n",
" return name+\"\\nCosts \"+price+\".\\n\"+inventory+\" remaining at \"+store+\"\\nYou can find this item in aisle \"+aisle+\".\";\n",
" }\n",
"\n",
" public void restock(int numberIn){\n",
" inventory += numberIn;\n",
" }\n",
"\n",
" public void sale(int numberSold){\n",
" inventory -= numberSold;\n",
" }\n",
"\n",
" public void refund(int numberSold){\n",
" inventory += numberSold;\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What we've done is begin to establish a **class hierarchy.** We know that the idea of a \"Product\" is very, very _general._ Products come in many different forms. We implement this idea by using an abstract class - it acts as a template for our general idea, and will never be instantiated itself - hence, no need for a constructor!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## So Many Products"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, what kind of products do stores sell? Well, we know lots of stores sell food! This is still a really general idea, so we know we want another abstract class. \n",
"\n",
"However, food also has an attribute unique to it; an expiry date! So only objects underneath food in our class hierarchy will have an expiry date. \n",
"\n",
"When we print our catalog, we're gonna want to know when our food expires. This means we need to add on to our toString() method. But how do we do this without copying and pasting it from the class above?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Food"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Food Class"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We're going to move down in our class hierarchy using the \"extends\" keyword. Here, we're saying that the idea of Food follows the idea of a Product; Food is a child of Product in our class hierarchy."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import java.util.Date;\n",
"\n",
"abstract public class Food extends Product {\n",
" public Date expiryDate = new Date();\n",
"\n",
" public boolean isExpired(Date d){\n",
" return expiryDate.before(d);\n",
" }\n",
"\n",
" public void eat(int numEaten){\n",
" inventory -= numEaten;\n",
" System.out.println(\"Stop eating our food!\");\n",
" }\n",
"\n",
" public String toString(){\n",
" String expired = (isExpired(new Date())) ? (\"\") : (\"not \");\n",
"\n",
" return super.toString()+\"\\nThis item is \"+expired+\"expired.\";\n",
" }\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Take note of our toString() method for the next important concept: The keyword \"super\". \n",
"\n",
"Whereas with \"this\", we would look to the top of the class to know what we're referring to ... here, we look **above** \"this\" in the class hierarchy, to its **parent** class. An easy way to do this is to look at **what class we extend**. So what we've done is called the Product method's toString() method, and then simply added onto it! \n",
"\n",
"N.b.: Please ignore the String expired = ... line of code. If you're curious, this is something called a \"ternary\" operation. It is just a shortened if statement, for all intents and purposes. This is simply for the purpose of printing if the food is expired, you do **not** need to know how to do this."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Produce"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Again, food is very general! We can continue to extend our idea of a Product. We went from Product to Food, and now we can go from Food to Produce.\n",
"\n",
"Produce has traits that not all food has; some of it is organic, and it will have a designation as either a fruit or a vegetable. Aside from that, it should share the same attributes and methods as Food (expiry date) and Product (everything else).\n",
"\n",
"You have to cut it off somewhere, so this is as far down our class hierarchy as we'll go; this is as specific as we'll get. We tell this to Java by using the \"final\" keyword, explaining that this class cannot be extended any further. We also implement a constructor so that we can instantiate the object.\n",
"\n",
"We also want to update our toString() method again! Question: is the \"super\" keyword here referring to Food, or Product?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public final class Produce extends Food{\n",
" public boolean organic;\n",
" public String type; // fruit or vegetable\n",
"\n",
" public Produce(double pIn, String nIn, Store sIn, int iIn, boolean oIn, String tIn){\n",
" price = pIn;\n",
" name = nIn;\n",
" store = sIn;\n",
" inventory = iIn;\n",
"\n",
" expiryDate.setDate(expiryDate.getDay() + 14);\n",
" aisle = 1;\n",
"\n",
" // extended variables\n",
" organic = oIn;\n",
" type = tIn;\n",
"\n",
" store.addProduct(this);\n",
" }\n",
"\n",
" public String toString(){\n",
" String printOrganic = (organic) ? (\"n organic \") : (\" \");\n",
"\n",
" return super.toString() + \"\\nThis is a\"+printOrganic+type+\".\";\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we're going to do this for Frozen foods. We won't spend as much time on this, as we're really just doing the same thing we did for Produce."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Frozen"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public final class Frozen extends Food{\n",
" int temperature;\n",
"\n",
" public Frozen(double pIn, String nIn, Store sIn, int iIn, int tIn){\n",
" price = pIn;\n",
" name = nIn;\n",
" store = sIn;\n",
" inventory = iIn;\n",
"\n",
" expiryDate.setMonth(expiryDate.getMonth() + 3);\n",
" aisle = 2;\n",
"\n",
" // extended variables\n",
" temperature = tIn;\n",
"\n",
" store.addProduct(this);\n",
" }\n",
"\n",
" public String toString(){\n",
" return super.toString() + \"\\nThis product must be frozen at a temperature of \"+temperature+\" degrees.\";\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Supplies"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Not all products are food, however. Let's define these other products as \"supplies.\" We won't spend very long on this either, as this is very similar to what we've done going from Food to Produce and Frozen.\n",
"\n",
"Supplies don't expire, but they do have a date until which you can return them."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Supplies Class"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import java.util.Date;\n",
"\n",
"abstract public class Supplies extends Product {\n",
" Date returnDate = new Date();\n",
"\n",
" public boolean canReturn(Date d){\n",
" return returnDate.after(d);\n",
" }\n",
"\n",
" public String toString(){\n",
" String expired = (canReturn(new Date())) ? (\"\") : (\"not \");\n",
"\n",
" return super.toString()+\"\\nYou may \"+expired+\"return this item. \";\n",
" }\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Clothes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Supplies is at the same level as Food on our hierarchy, and Clothes will be on the same level as Frozen/Produce (but underneath Supplies)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public final class Clothes extends Supplies {\n",
" String material; // cotton, denim\n",
"\n",
" public Clothes(double pIn, String nIn, Store sIn, int iIn, String mIn){\n",
" price = pIn;\n",
" name = nIn;\n",
" store = sIn;\n",
" inventory = iIn;\n",
"\n",
" returnDate.setDate(returnDate.getDay() + 14);\n",
" aisle = 3;\n",
"\n",
" // extended variables\n",
" material = mIn;\n",
"\n",
" store.addProduct(this);\n",
" }\n",
"\n",
" public String toString(){\n",
" return super.toString() + \"This is made of \"+material+\".\";\n",
" }\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Furniture"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Furniture will be on the same level as clothes, with a different return date."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public final class Furniture extends Supplies {\n",
" public String leather;\n",
"\n",
" public Furniture(double pIn, String nIn, Store sIn, int iIn, String lIn){\n",
" price = pIn;\n",
" name = nIn;\n",
" store = sIn;\n",
" inventory = iIn;\n",
"\n",
" returnDate.setMonth(returnDate.getMonth() + 1);\n",
" aisle = 3;\n",
"\n",
" // extended variables\n",
" leather = lIn;\n",
"\n",
" store.addProduct(this);\n",
" }\n",
"\n",
" public String toString(){\n",
" return super.toString() + \"This product is made of \"+leather+\" leather.\";\n",
" }\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Testing Out Some Stores"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's test out a few different stores. We're going to use the idea of polymorphism to see just how useful it is! Remember in our Store class, we have our catalog. This catalog is an array of **Products.** Here in our code, we are going to create apple and pear. We call the Produce constructors... \n",
"\n",
"But we store them in Product variables! This lets them be held in the Store's Product catalog, as it is an array of Products ... but they still maintain their unique functionality!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Store loblaws = new Store(\"Loblaws\", \"2210 Bank St.\");\n",
"\n",
"Product apple = new Produce(1.25, \"Apple\", loblaws, 100, true, \"fruit\");\n",
"Product pear = new Produce(1.10, \"Pear\", loblaws, 50, false, \"fruit\");\n",
"\n",
"loblaws.displayCatalog();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is really important!! Notice how even though in our Store class, we have an array of Products, but when we print the items in the catalog, they're acting like Produce!\n",
"\n",
"Let's look at this through another example. The exact same thing happens for our Ikea store!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Store ikea = new Store(\"Ikea\", \"2685 Iris St.\");\n",
"\n",
"Product chair = new Furniture(50.0, \"Chair\", ikea, 10, \"genuine\");\n",
"Product couch = new Furniture(250.0, \"Couch\", ikea, 10, \"bonded\");\n",
"\n",
"ikea.displayCatalog();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is the power of polymorphism in Java. We've created a Store that takes an array of \"Products,\" which is a very general template. We can now use this in a way to easily setup a store that sells food, or a store that sells furniture, and our Store class will behave properly while maintaining the uniqueness of a furniture object versus a produce object."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Ignore this"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public class Product { }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Setting Up our Shopify Store"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's briefly talk about interfaces. An interface is a collection of methods shared many classes must implement themselves in unique ways."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public interface Shopify {\n",
"\n",
" public void deliver(String address, int quantity);\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's open up a new online Shopify store so that we can ship people their products. We do this by using \"implements,\" and then writing code for the method in our class."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"abstract public class Product implements Shopify {\n",
" protected double price;\n",
" protected String name;\n",
" protected Store store;\n",
" protected int inventory;\n",
" protected int aisle;\n",
"\n",
" public String toString() {\n",
" return name + \"\\nCosts \" + price + \".\\n\" + inventory + \" remaining at \" + store + \"\\nYou can find this item in aisle \" + aisle + \".\";\n",
" }\n",
"\n",
" public void restock(int numberIn) {\n",
" inventory += numberIn;\n",
" }\n",
"\n",
" public void sale(int numberSold) {\n",
" inventory -= numberSold;\n",
" }\n",
"\n",
" public void refund(int numberSold) {\n",
" inventory += numberSold;\n",
" }\n",
"\n",
" public void deliver(String address, int quantity) {\n",
" System.out.println(\"Delivering \" + quantity + \" \" + this.name + \"(s) to \" + address);\n",
" inventory -= quantity;\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Boxing Day Sales"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's also take a look at another way we can use polymorphism. We'll define a Discount class, which could be used to hold all of our sales. For now, let's put on a very late Boxing Day sale on all of our supplies. We force the method to take in a Supplies object, and make it static such that the discount will be applied to all instances of the class."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"public class Discount {\n",
"\n",
" public static void boxingDaySale(Supplies s) {\n",
" s.price *= 0.5;\n",
" System.out.println(s.name + \" is now on sale for \" + s.price + \".\");\n",
" }\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Our Complete Store"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can put together all of the concepts we've built. We can create a Walmart, whose catalog will hold many Products of different types. We will then apply a sale on our couches, and deliver some through our Shopify store."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Store walmart = new Store(\"Walmart\", \"2210 Bank Street\");\n",
"\n",
"Product apple = new Produce(1.25, \"Apple\", walmart, 100, true, \"fruit\");\n",
"Product delisso = new Frozen(6.99, \"Pizza\", walmart, 25, -5);\n",
"Product couch = new Furniture(200.00, \"Couch\", walmart, 10, \"genuine\");\n",
"Product shirt = new Clothes(10.00, \"Shirt\", walmart, 50, \"cotton\");\n",
"\n",
"System.out.println(\"All couches must go!\");\n",
"Discount.boxingDaySale((Supplies)couch);\n",
"\n",
"System.out.println();\n",
"walmart.displayCatalog();\n",
"\n",
"\n",
"couch.deliver(\"Carleton U\", 1);\n",
"\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Java",
"language": "java",
"name": "java"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment