Struggling with Objected-Oriented Method - java

I can't figure it out what getExits() needs to be in order to get the output requested by the problem.
//Constructor
public class Room {
private String name;
private String description;
private Room north;
private Room east;
private Room south;
private Room west;
public Room (String name, String description){
this.name = name;
this.description = description;
}
public Room getEast(){
return this.east;
}
public String getExits (){
//
}
public String getName(){
return this.name;
}
public Room getNorth(){
return this.north;
}
public Room getWest(){
return this.west;
}
public Room getSouth(){
return this.south;
}
public void setExits (Room n, Room e, Room w, Room s){
this.north = n;
this.east = e;
this.west = w;
this.south = s;
}
public String toString(){
return String.format("%s\n%s\n%s", this.name, this.description,getExits());
}
}
//Main Method
public class Tester{
public static void main(String []args){
Room hall = new Room ("Hall", "It's Dark");
Room bed = new Room ("Bed", "Tiny Room");
Room bath = new Room ("Bath", "Toilets here");
Room dine = new Room ("Dine", "Table and chairs");
hall.setExits(bed, bath, dine, null);
System.out.println(hall);
}
}
Output expected:
Hall
It's Dark
North: Dine
East: Bath
West: Dining

The 'Object Oriented' way of getting what you want would be to override the toString() method in your Room class such that it returns the name of the room.
You then modify the getExits(), like so:
public String getExits (){
StringBuilder sb = new StringBuilder();
if(this.north != null) sb.append(this.north.toString()).append(" North") else sb.append("No Exit for: North");
...
return sb.toString();
}
....
public class Room {
private String name;
...
#Override
public String toString() {
return this.name;
}
}

exit isn't something you can describe with a String. In the OO world, it should be a reference to a more meaningful object. I would go with
public Collection<Room> getExits();
or
public Map<String, Room> getExits();
which accurately describes where you can get from the hall. Here, we are assuming that "exit" is a doorway to another room.
You could return
Arrays.asList(northRoom, eastRoom, southRoom, westRoom);
or
Map<String, Room> map = new HashMap<>();
map.put("north", northRoom);
...
return map;
Then you would be able to provide any String representation from the returned collection.
It's like a sign placed in the hall to help people navigate. Even though it can be replaced with another sign (a more detailed/accurate one), the structure of the building is constant, and you aren't altering it. You are just representing it differently.
String simpleSign = "You can go to: " + getExits().stream().map(Object::toString).collect(Collectors.join(", "));
or
String detailedSign = "Directions to go: " + getExits().entrySet().stream().map(e -> e.getKey() + " -> " + e.getValue().toString()).collect(Collectors.join("\n"));

Here's one way of doing things. It's a little awkward because you have to check for null for each case - if that's not the case for you, you can remove those checks.
public String getExits (){
List<String> exits = new ArrayList<>();
if (north != null) exits.add("North: " + north.name);
if (south != null) exits.add("South: " + south.name);
if (east != null) exits.add("East: " + east.name);
if (west != null) exits.add("West: " + west.name);
return String.join("\n", exits);
}

Related

Recursion in java with objects of courses and prerequisites

Good day, is there a more efficient way to do this problem with recursion than using a switch statement. In my courses class I have a recursive association of course and a prerequisite then a set the preReqs in the PreReqs class. How can I print out all of preReqs of a class when a user enter a class which has preReqs? Right now I am in the process of using a switch statement and printing each preReq individually but is there a better way to do this still using recursion?
An example out of this: If the user types that course, all of the preReqs will print out too.
ACS-3947 Algorithm Design
prereq: ACS-2947 Data Structures and Algorithms
ACS-2947 Data Structures and Algorithms
prereq: ACS-1904 Programming Fundamentals II
ACS-1904 Programming Fundamentals II
prereq: ACS-1903 Programming Fundamentals I
ACS-1903 Programming Fundamentals I
no prereq
Course class:
import java.util.*;
public class Course
{
protected String courseNumber;
protected String courseName;
protected Course prerequisite;
public Course(){
courseNumber = courseName = "Unknown";
prerequisite= null;
}
public Course (String cn, String num){
this.courseNumber=num;
this.courseName=cn;
}
public String getCourseNumber(){
return courseNumber;
}
public String getCourseName(){
return courseName;
}
public Course getPreReq(){
return prerequisite;
}
public void setCourseNumber(String courseNumber){
this.courseNumber=courseNumber;
}
public void setCourseName(String courseName){
this.courseName=courseName;
}
public void setPreReq(Course pr){
prerequisite =pr;
}
}
PreReq class:
import java.util.*;
import java.io.*;
public class Prereqs
{
public static void main (String [] args){
Scanner kb = new Scanner (System.in);
Course nineteen03 = new Course ("Programming Fundamentals I","ACS-1903");
Course nineteen04 = new Course ("Programming Fundamentals II"," ACS-1904");
Course two47 = new Course ("Data Structures and Algorithms","ACS-2947 ");
Course three47 = new Course ("Algorithm Design","ACS-3947");
Course two09 = new Course ("Internet Programming","ACS-2909");
Course three09 = new Course ("Advanced Internet Programming ","ACS-3909");
nineteen04.setPreReq(nineteen03);
two47.setPreReq(nineteen04);
three47.setPreReq(two47);
two09.setPreReq(nineteen03);
three09.setPreReq(nineteen03);
System.out.println("Enter course number with the format: AAA-999");
String input = kb.next();
validate(input);
}
public static void course(Course nineteen04, Course nineteen03,Course two47, Course three47, Course two09, Course three09, String input ){
Course c1 = nineteen04.getPreReq();
Course c2 = two47.getPreReq();
Course c3 = three47.getPreReq();
Course c4 = two09.getPreReq();
Course c5 = three09.getPreReq();
switch (input){
case "ACS-1904":
System.out.println(nineteen04.getCourseName()+" "+nineteen04.getCourseNumber());
System.out.println("preReq: " + c1.getCourseName()+ " "+ c1.getCourseNumber());
}
}
public static String validate (String input)
{
String arg = input;
boolean valid = arg.length()==7;
if (!valid){
throw new IllegalArgumentException("Not the correct format: AAA-999");
}
valid = arg.charAt(3) == '-';
if(!valid) {
throw new IllegalArgumentException("Not the correct format: AAA-999");
}
for(int i=0; i < 3 && valid; i++){
valid = ((i == 3 && Character.isLetter(arg.charAt(i))));
}
for(int i=3; i < 3 && valid; i++){
valid = ((i==6 && Character.isDigit(arg.charAt(i))));
}
return arg;
}
}
A recursive method needs to contain a condition which terminates the recursion. Your list of courses and their prerequisites remind me of a linked list where each course points to its prerequisite. The list terminates when we reach a course that has no prerequisite. The below code is your Course class with the addition of a main method (imported from your Prereqs class) and the recursive method which I named requirements(). I also added method toString() to make the display of the list of courses and their prerequisites more "human readable". You can experiment by changing the course passed to the initial invocation of method requirements().
public class Course {
protected String courseNumber;
protected String courseName;
protected Course prerequisite;
public Course(){
courseNumber = courseName = "Unknown";
prerequisite= null;
}
public Course (String cn, String num){
this.courseNumber=num;
this.courseName=cn;
}
public String getCourseNumber(){
return courseNumber;
}
public String getCourseName(){
return courseName;
}
public Course getPreReq(){
return prerequisite;
}
public void setCourseNumber(String courseNumber){
this.courseNumber=courseNumber;
}
public void setCourseName(String courseName){
this.courseName=courseName;
}
public void setPreReq(Course pr){
prerequisite =pr;
}
public String toString() {
return courseNumber + " " + courseName;
}
private static void requirements(Course c) {
if (c == null) {
return;
}
else {
System.out.println(c);
requirements(c.getPreReq());
}
}
public static void main(String[] args) {
Course nineteen03 = new Course ("Programming Fundamentals I","ACS-1903");
Course nineteen04 = new Course ("Programming Fundamentals II"," ACS-1904");
Course two47 = new Course ("Data Structures and Algorithms","ACS-2947 ");
Course three47 = new Course ("Algorithm Design","ACS-3947");
Course two09 = new Course ("Internet Programming","ACS-2909");
Course three09 = new Course ("Advanced Internet Programming ","ACS-3909");
nineteen04.setPreReq(nineteen03);
two47.setPreReq(nineteen04);
three47.setPreReq(two47);
two09.setPreReq(nineteen03);
three09.setPreReq(nineteen03);
requirements(three09);
}
}
Running the above code displays the following:
ACS-3909 Advanced Internet Programming
ACS-1903 Programming Fundamentals I

Is there a way to make Dozer map fields without getter or setters? (Or, what mapper can do this?)

Here's an article on Dozer: https://www.baeldung.com/dozer. It's a mapper that uses reflection to map same-name fields from one object to another (of a completely unrelated class).
I was wondering if this works flexibly with private fields, getters, and setters. That is,
Will private String a map to another object's private String a without either having any getters or setters?
What if only one side has a getter or setter (and the private field is named something different to make sure it's not directly accessing private fields)?
What if one has a getter and the other has a setter for totally mismatching private fields? (But the getter and setter names match.)
I wrote a test program to run in https://www.jdoodle.com/online-java-compiler:
import org.dozer.DozerBeanMapper;
public class Main {
public static class MySource {
// a -> a
private String a;
// getB() -> b
private String hidden_b;
public String getB() { return hidden_b; }
// c -> setC(c)
private String c;
// getD() -> setD(d)
private String hidden_d;
// proper getters and setters on both sides
private String proper;
public String getProper() { return proper; }
// public void setProper(String proper_) { proper = proper_; }
public MySource() {
a = "A Room with a View";
hidden_b = "The Bridge of San Luis Rey";
c = "Civilwarland in Bad Decline";
hidden_d = "Darkness at Noon";
proper = "This should copy, at minimum.";
}
public void print() {
System.out.println("Source");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("hidden_b = " + hidden_b);
System.out.println("c = " + c);
System.out.println("hidden_d = " + hidden_d);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static class MyTarget {
private String a;
private String b;
private String hidden_c;
private String hidden_e;
public void setC(String param) { hidden_c = param; }
public void setD(String param) { hidden_e = param; }
private String proper;
// public String getProper() { return proper; }
public void setProper(String proper_) { proper = proper_; }
public MyTarget() {}
public void print() {
System.out.println("Target");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("hidden_c = " + hidden_c);
System.out.println("hidden_e = " + hidden_e);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static void main(String args[]) {
MySource s = new MySource();
s.print();
System.out.println("Now dozing...");
System.out.println("");
MyTarget t = new DozerBeanMapper().map(s, MyTarget.class);
t.print();
}
}
Note that to run the above code you must add a maven dependency:
Group ID: net.sf.dozer
Artifact ID: dozer
Version: 5.5.1
And also you must try executing a few times because of random timeouts depending on whether the dependency loads fast enough.
Anyway, my output was:
Source
================================
a = A Room with a View
hidden_b = The Bridge of San Luis Rey
c = Civilwarland in Bad Decline
hidden_d = Darkness at Noon
--------------------------------
proper = This should copy, at minimum.
Now dozing...
Target
================================
a = null
b = null
hidden_c = null
hidden_e = null
--------------------------------
proper = This should copy, at minimum.
So, it appears Dozer only works through a getter on the source and a setter on the target, which is disappointing. Or, I'm not using it correctly!
Is there a way to make Dozer more flexible? Or, another mapper library that can achieve this?
Okay, here are my findings. Hopefully this helps someone.
Dozer 5.5.1 was supposed to be able to do this via "class-level is-accessible." However, there was a bug. It was fixed for future releases, e.g. Dozer 6.1+. (The package moved to a new group, org.github.dozermapper.) The steps were a little complicated though, and eventually I gave up to try ModelMapper, which was much nicer. So here's my code.
Include this package:
Group ID: org.modelmapper
Artifact ID: modelmapper
Version: 2.3.2
Here's how to use it:
import org.modelmapper.ModelMapper;
import org.modelmapper.config.Configuration;
public class Main {
public static class MySource {
// a -> a
private String a;
// getB() -> b
private String hidden_b;
public String getB() { return hidden_b; }
// c -> setC(c)
private String c;
// getD() -> setD(d)
private String hidden_d;
// proper getters and setters on both sides
private String proper;
public String getProper() { return proper; }
// public void setProper(String proper_) { proper = proper_; }
public MySource() {
a = "A Room with a View";
hidden_b = "The Bridge of San Luis Rey";
c = "Civilwarland in Bad Decline";
hidden_d = "Darkness at Noon";
proper = "This should copy, at minimum.";
}
public void print() {
System.out.println("Source");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("hidden_b = " + hidden_b);
System.out.println("c = " + c);
System.out.println("hidden_d = " + hidden_d);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static class MyTarget {
private String a;
private String b;
private String hidden_c;
private String hidden_e;
public void setC(String param) { hidden_c = param; }
public void setD(String param) { hidden_e = param; }
private String proper;
// public String getProper() { return proper; }
public void setProper(String proper_) { proper = proper_; }
public MyTarget() {}
public void print() {
System.out.println("Target");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("hidden_c = " + hidden_c);
System.out.println("hidden_e = " + hidden_e);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static void main(String args[]) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
MySource s = new MySource();
s.print();
System.out.println("Now dozing...");
System.out.println("");
MyTarget t = modelMapper.map(s, MyTarget.class);
t.print();
}
}
Here's my output:
Source
================================
a = A Room with a View
hidden_b = The Bridge of San Luis Rey
c = Civilwarland in Bad Decline
hidden_d = Darkness at Noon
--------------------------------
proper = This should copy, at minimum.
Now dozing...
Target
================================
a = A Room with a View
b = The Bridge of San Luis Rey
hidden_c = Civilwarland in Bad Decline
hidden_e = null
--------------------------------
proper = This should copy, at minimum.
The fourth case didn't copy over but I don't really care about that case. I think it can easily achieved with a different ModelMapper configuration though. Maybe try LOOSE copying. Or worst case, manually bind the getter and setter methods in the config.
Dozer by default uses getters and setters, however you can tell Dozer (via mapping) to access the fields directly
http://dozer.sourceforge.net/documentation/custommethods.html
BTW, Dozer 5 and 6 contains an API based mapping as well.

HashMap Issuses

Edited the getTypeString method in the Flowers class now I just get the pointer to the object
I'm working on a project for one of my classes. I haven't worked with HashMap before and I need to use one. In this java class I'm trying to print out the full description that I have set. But it wont print the HashMap value from the key. I have tried to use some code from my book, but with no luck.
This is the class that is calling the class that has the HashMap:
public class Garden
{
private Gardener gardener;
private Tools tools;
private Flowers flowers;
/**
* Constructor for objects of class Garden
*/
public Garden()
{
gardener = new Gardener();
tools = new Tools();
Flowers rose;
rose = new Flowers("a beautiful red flower");
rose.setFlower("red", rose);
System.out.println(rose.fullDescription());
}
}
Edited the getTypeString method
This is the class that is using the HashMap:
import java.util.Set;
import java.util.HashMap;
public class Flowers
{
private String fDescription;
private HashMap<String, Flowers> flowers;
/**
* Constructor for objects of class Flowers
*/
public Flowers(String fDescription)
{
this.fDescription = fDescription;
flowers = new HashMap<String, Flowers>();
}
public void setFlower(String color, Flowers type)
{
flowers.put(color, type);
}
public String flowerDescription()
{
return fDescription;
}
public String fullDescription()
{
return "The "+ getTypeString() + " is " + fDescription;
}
private String getTypeString()
{
String des = "";
Collection<Flowers> vals = flowers.values();
for(Flowers f : vals){
des += f;
}
return des;
}
}
The problem, I think, is in the getTypeString() function. Can anyone point me in the right direction?
Edit
I removed the getTypeString method and edited the fullDescription method:
public String fullDescription()
{
return "The "+ type + " is " + fDescription;
}
now I'm trying to get the 'HashMap' to print the objects like so:
"Flower [type= type, description= Description "]"
using thes methods:
public static void printHashMap()
{
System.out.println("hashmap: " + flowers);
}
#Override
public String toString()
{
return "Flower [type=" + type + ", description=" + fDescription ]";
}
From your post, what I have understood is that you want to print the description of flowers. So I think you can try something like:
private String getTypeString(){
String des = "";
Collection<String> vals = flowers.values();
for(String f : vals){
des = des + f.flowerDescription();
}
return des;
}
Override the toString method in your class
Declare a toString method with the following modifiers and return type:
#Override
public String toString() {
return this.fDescription;
}
Implement the method so that it returns a string.

One of my classes will not output anything

so I need some advice, I have been working on some code for quite a while and I can never seem to find out why my code is screwing up terribly. It seems as if one of the toString lines in my Product class is not working properly. Here is the code:
import java.util.ArrayList;
public class lab24ArrayList
{
public static void main(String[]args)
{
ShoppingCart cart = new ShoppingCart();
Product hat = new Product ("Hat", 10);
Product scarf = new Product ("Scarf", 8);
Product legos = new Product ("Legos", 19);
Product dvd = new Product ("DVD", 12);
System.out.println("Removing DVD: "+cart.remove(dvd));
cart.add(hat);
cart.add(scarf);
cart.remove(scarf);
System.out.println("Removing Scarf: " +cart.remove(scarf));
cart.add(legos);
cart.add(dvd);
cart.add(legos);
System.out.println(cart);
}
}
class ShoppingCart
{
ArrayList <Product> cart;
public ShoppingCart()
{
cart = new ArrayList<Product>();
}
public int size()
{
int k = cart.size();
return k;
}
public void add(Product p)
{
cart.add(p);
}
public Product remove(Product p)
{
if(cart.contains(p))
{
cart.remove(p);
return p;
}
else
return null;
}
}
class Product
{
private String name;
private double price;
public Product(String _name, double _price)
{
name = _name;
price = _price;
}
public String getName() {return name;}
public double getPrice() {return price;}
public String toString() {return name + ": $"+price;}
}
When I put it in the compiler, all I get is this:
Removing DVD: null
Removing Scarf: null
ShoppingCart#c2f0bd7
When I need to get this:
Removing DVD: null
Removing Scarf: Scarf: $8
Items: 6
Total: $60.00
Hat: $10
Legos: $19
DVD: $12
Legos: $19
You're missing a toString() method on your ShoppingCart, that's why you get ShoppingCart#c2f0bd7. Override toString() in the ShoppingCartclass to build a string from the items within it.
You're also removing the Scarf twice, once here cart.remove(scarf) then also in System.out.println("Removing Scarf: " +cart.remove(scarf)).
To clarify how to print out the cart, you'll want to create a toString method in ShoppingCart similar to what you've done in Product:
public static String toString() {
StringBuilder stringBuilder = new StringBuilder();
for(Product product : cart) {
stringBuilder.append(product);
}
return stringBuilder.toString();
}
That creates a StringBuilder, loops through each product in the cart and appends it to the StringBuilder. You then return that string.

How to return a private variable

Ok so I'm trying to get a better understanding of how to return a private variable from a class that I have created. I've only provided a small snippet of my main program to explain my question, so if more information is needed please let me know. My goal is to return a string from the class (working great), but also be able to return the private variables individually as needed (example used below is "flight_number").
public class Flights {
private String dest_city, dest_state, departureDate, departureTime;
private int flight_number;
public Flights(String city, String state, String dDate, String dTime, int flightNumber) {
dest_city = city;
dest_state = state;
departureDate = dDate;
departureTime = dTime;
flight_number = flightNumber;
}
public String toString() {
return "Flight number: " + flight_number + " Destination: " + dest_city + "," + dest_state + " Departing on:" + departureDate + " at" + departureTime + ".";
}
}
public class dummy {
public static void main(String[] args) {
// Uses the constructor to set values
Flights flight1 = new Flights("Houston", "Texas", "12/20/2014", "12:40 pm", 100);
System.out.println(flight1);
System.out.println(flight_number); // Error: `flight_number` cannot be resolved to a variable.
}
}
You need to add a public getter in Flights and call it from main:
public class Flights {
// all the private fields
public int getFlightNumber() {
return this.flight_number;
}
}
In Main:
public static void main(String[] args) {
Flights flight1 = new Flights("Houston", "Texas"); //...
System.out.println(flight1);
System.out.println(flight1.getFlightNumber()); // call the getter
}
You should start with an editor like eclipse and that should help you get started quickly. Getters and Setters is what you need, but start with Eclipse and you should do better.

Categories

Resources