Override void method with calculation of private access variable - java

I am doing an assignment requiring me to create a program to store information on tools. The initial class is used to test the results of other classes. The other 4 are made up of a super class called Equipment and has to be abstract, and then 3 child classes.
I have managed to get the equipment class sorted (I think), but can not work out how to override the replacementYear property which is private as the math to return the result changes for each class.
Math for the battery powered class is
Replacement Year = Length of Warranty + Purchase Year
Do I need to create an object to complete the math in each class and use a return statement with the replacementYear I am overriding?
Sorry if it not extremely clear but below is the code.
//Parent
abstract class Equipment {
private String make;
private String model;
private int purchaseYear;
private String replacementYear;
//Constructor for Equipment
public Equipment()
{
make = " ";
model = " ";
purchaseYear = 0;
}
abstract void replacementYear();
public String getMake()
{
return make;
}
public void setMake(String newMake) {
this.make = newMake;
}
public String getModel()
{
return model;
}
public void setModel(String newModel) {
this.model = newModel;
}
public int getPurchaseYear()
{
return this.purchaseYear;
}
}
The child class:
class BatteryPoweredEquipment extends Equipment {
private int warranty = 0;
//Constructor
public void BatteryPoweredEquipment()
{ }
//set & get warranty
public int getWarranty()
{
return warranty;
}
public void setWarranty(int newWarranty)
{
this.warranty = newWarranty;
}
//override
#Override
void replacementYear() {
System.out.println(warranty + this.getPurchaseYear());
}
}

yea, if replacement year needs to computed differently for each type of equipment, then make this method abstract in the abstract superclass so that each extending class can override this to have their custom logic

First of all, you need to create an Equipment constructor that actually accepts all its properties, otherwise, your subclasses would be a pain to use (you would need to call each setter to actually build the object). Talking about setters, that is something you don't really or want (I guess that make, model, purchaseYear do not really change after the Equipment is built and replacementYear should be computed while constructing the object the first time). Additionally, please make use of the new Java Time API (which includes Year and Period instead of modeling years and warranty period as int). After doing this your Equipment class would look as follows:
import java.time.Year;
abstract class Equipment {
private String make;
private String model;
private Year purchaseYear;
private Year replacementYear;
//Constructor for Equipment
public Equipment(String make, String model, Year purchaseYear, Year replacementYear) {
this.make = make;
this.model = model;
this.purchaseYear = purchaseYear;
this.replacementYear = replacementYear;
}
public String getMake() {
return make;
}
public String getModel() {
return model;
}
public Year getPurchaseYear() {
return this.purchaseYear;
}
public Year getReplacementYear() {
return replacementYear;
}
}
Now you also need to adjust your child classes. BatteryPoweredEquipment would look as follows:
import java.time.Period;
import java.time.Year;
class BatteryPoweredEquipment extends Equipment {
private Period warranty;
public BatteryPoweredEquipment(String make, String model, Year purchaseYear, Period warranty) {
super(make, model, purchaseYear, purchaseYear.plus(warranty));
this.warranty = warranty;
}
public Period getWarranty() {
return warranty;
}
}

Related

Constructor Chaining with subclasses in Java

Just a question RE: Constructor Chaining in subclasses that I can't find a good answer on and I'm confusing myself a bit with.
I'm making a basic little Text Based RPG for some practice and I'm going through my constructors for an abstract class and have the constructors from 0-4 params chained together like below
abstract class Creature {
// Fields
private String name;
private int lifeForce;
private int strength;
private int agility;
// Constructors + Chaining
public Creature() {
this("Unknown")
}
public Creature(String name) {
this(name, 100);
}
public Creature(String name, int lifeForce) {
this(name, lifeForce, 10);
}
public Creature(String name, int lifeForce, int strength) {
this(name, lifeForce, strength, 10);
}
public Creature(String name, int lifeForce, int strength, int agility) {
this.name = name;
this.lifeForce = lifeForce;
this.strength = strength;
this.agility = agility;
}
My confusion is how best to format the constructors of a subclass of creature, for example this simple Person class introduces two new fields. There's definitely too much repetition if I write the constructors like this
// Constructors + Chaining
public Person() {
super("Unknown");
this.skillClass=new Mage();
this.dialogue="...";
}
public Person(String name) {
super(name);
this.skillClass=new Mage();
this.dialogue="...";
} etc etc etc
I suppose I could restrict the constructors to limit the repetition but I'm mostly just wondering if there's good best practice that I'm missing here.
Any and all suggestions welcome and if anyone has any good resources to recommend that go deeper than the usual
Class B extends Class A
examples I'd massively appreciate.
In situations like this one when you need to use multiple constructors with different parameters, it is recommended to use the builder pattern like this :
abstract class Creature {
// Fields
private String name;
private int lifeForce;
private int strength;
private int agility;
private Creature(Builder<?> builder) {
this.name = builder.name;
this.lifeForce = builder.lifeForce;
// Add the other attributes here.
}
public static abstract Builder extends Builder<T extends Builder<T>> {
private String name;
private int lifeForce;
private int strength;
private int agility;
public Builder(//here you put the attributes that you need to have in all instances) {
// here you do the affectations.
}
// now you need to make the functions that set each property :
public Builder lifeForce(int lifeForce) {
this.lifeForce = lifeForce;
return this;
}
// you do the same thing for all the other attributes.
...
public Creature build() {
return new Creature(this);
}
}
}
So for the explanation : This pattern will allow you to create instances of your class by setting only the needed attributes.
As here you have subclasses the builder pattern will be little bit more harder to understand but it is the perfect solution in such situation.
We need to apply the builder pattern also for every subclasse so let's do it for the person class :
public class Person extends Creature {
private int anotherField;
public Person(Builder builder) {
super(builder);
this.anotherField = anotherField;
}
public static Builder extends Creature.Builder<Builder> {
public Builder(//add the fieldHere if it is needed in all class instances) {
// if the field is not mandatory you can omit this constructor but you need to put the function below.
}
public Builder anotherField(int anotherField) {
this.anotherField = anotherField;
}
public Person build() {
return new Person(this);
}
}
Now let me show you how tricky is this solution :
1/ declare person with 2 fields :
Person p1 = Person.Builder().name("name").anotherField(0).build();
2/ declare another one with just one field
Person p2 = Person.Builder().agility(1000).build();
Remark : In these two examples, i supposed that your builders' constructors don't have parameters. If for example the name is mandatory field :
Person p3 = Person.Builder("name").anotherField(0).build();
I wish that you had the idea about using builder pattern.

Create tasks[] an array of task

My current problem is that I am assigned to created a program that should within the private fields assign tasks[] an array of task. Then within the constructor, that creates the task[] array, giving it the capacity of INITIAL_CAPAITY, and setting numTasks to zero.
I am new and confused on I can tackle this problem
I have tried declaring it within the constructor but there has been no luck.
Task.java
public class Task {
private String name;
private int priority;
private int estMinsToComplete;
public Task(String name, int priority, int estMinsToComplete) {
this.name=name;
this.priority=priority;
this.estMinsToComplete = estMinsToComplete;
}
public String getName() {
return name;
}
public int getPriority() {
return priority;
}
public int getEstMinsToComplete() {
return estMinsToComplete;
}
public void setName(String name) {
this.name = name;
}
public void setEstMinsToComplete(int newestMinsToComplete) {
this.estMinsToComplete = newestMinsToComplete;
}
public String toString() {
return name+","+priority+","+estMinsToComplete;
}
public void increasePriority(int amount) {
if(amount>0) {
this.priority+=amount;
}
}
public void decreasePriority(int amount) {
if (amount>priority) {
this.priority=0;
}
else {
this.priority-=amount;
}
}
}
HoneyDoList.java
public class HoneyDoList extends Task{
private String[] tasks;
//this issue to my knowledge is the line of code above this
private int numTasks;
private int INITIAL_CAPACITY = 5;
public HoneyDoList(String tasks, int numTasks, int INITIAL_CAPACITY,int estMinsToComplete, String name,int priority) {
super(name,priority,estMinsToComplete);
numTasks = 0;
tasks = new String[]{name,priority,estMinsToComplete};
//as well as here^^^^^^^^
}
My expected result is to be able to print out the list through honeydo class. I need to manipulate the code a bit more after adding a few other methods.
Your problem is that your constructor parameter tasks has the same name as that field of your class.
So you assign to the method parameter in your constructor, not to the field. And luckily those two different "tasks" entities have different types, otherwise you would not even notice that something is wrong.
Solution: use
this.tasks = new String...
within the body of the constructor!
And the real answer: you have to pay a lot attention to such subtle details. And by using different names for different things you avoid a whole class of issues!
Also note: it sounds a bit strange that a class named Task contains a list of tasks, which are then strings. The overall design is a bit weird...

Trying to store Bukkit ItemStack field to a file but ItemStack is not Serrializable

ItemStack is not serializable and I'm trying to save an object called Objective with an ItemStack field to a file but since ItemStack is not serializable this does not work. I tried extending ItemStack and implementing Serializable and changing the field to my new serializable sub class but this also did not work. Here are the relevant parts of my original code:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import org.bukkit.inventory.ItemStack;
public class Objective implements Serializable {
private static final long serialVersionUID = -2018456670240873538L;
private static ArrayList<Requirement> requirements = new ArrayList<>();
private String name;
private Requirement requirement;
private ItemStack reward;
private int tillComplete;
private boolean complete;
public Objective(String name, int requirementIndex, int tillComplete, ItemStack reward) {
if(requirements.isEmpty()) {
requirements.add(Requirement.kill_Skeletons);
requirements.add(Requirement.kill_Spiders);
requirements.add(Requirement.kill_Zombies);
}
this.name = name;
this.requirement = requirements.get(requirementIndex);
this.tillComplete = tillComplete;
this.reward = reward;
complete = false;
}
public String getName() {
return name;
}
public Object getRequirement() {
return requirement;
}
public static ArrayList<Requirement> getRequirements() {
return requirements;
}
public static void setRequirements(ArrayList<Requirement> requirements) {
Objective.requirements = requirements;
}
public int getTillComplete() {
return tillComplete;
}
public void setTillComplete(int tillComplete) {
this.tillComplete = tillComplete;
}
public void setName(String name) {
this.name = name;
}
public void setRequirement(Requirement requirement) {
this.requirement = requirement;
}
public void setReward(ItemStackSerializable reward) {
this.reward = reward;
}
public void setComplete(boolean complete) {
this.complete = complete;
}
public ItemStack getReward() {
return reward;
}
public boolean isComplete() {
return complete;
}
}
Elsewhere in my code this line of code:
ItemStack reward = new ItemStack(Material.DIAMOND_SWORD);
Objective objective = new Objective(args[1] ,Integer.parseInt(args[2]), Integer.parseInt(args[3]), reward);
is giving me this error:
java.io.NotSerializableException: org.bukkit.inventory.ItemStack
How can I serialize this object? I need to store it but Java wont let me. Thanks for your help. If you need anymore code snippets or other information please let me know.
This is most likely an XY problem. ItemStack is not serializable, as it represents an actual stack of items at runtime. This would not make sense to store in a file. It might be worth looking at the ConfigurationSerializable interface, which is implemented by ItemStack, but I don't think you need that here.
In your example, the ItemStack that you are trying to serialize doesn't have any metadata. It is a single diamond sword. If all your rewards are just a single item, all you need to save is the Material and you can create a new ItemStack from that Material every time you want to give a player a reward. Since Material is an enum, it is serializable by default.
You could also serialize an int for stack size if some of your rewards require a stack of multiple items. If you need any metadata, serialize the data needed to construct that at runtime. For example, to give an item lore, you would store a List<String> (with a serializable implementation of List).

Java method to return multiple values

I have a situation where I would like to return 2 values from a method. I am trying to figure out how to do this in Java. In C# I would just use 2 out parameters or a struct in this case but not sure what is best to do for Java (other than Pair as I may have to change this to 3 values, or having to create a new class to return object).
My example is this:
public void myMethod(Signal signal){
MyEnum enum = MyEnum.DEFAULT;
String country = "";
// based on signal, I need to get 2 values, one is string, other is
// an enumeration
if (signal.getAction() == "Toyota"){
enum = MyEnum.TOYOTA;
country = "Japan";
} else if (signal.getAction() == "Honda"){
enum = MyEnum.HONDA;
country = "Japan";
} else if (signal.getAction() == "VW"){
enum = MyEnum.VW;
country = "Germany";
} else {
enum = MyEnum.DEFAULT;
country = "Domestic";
}
// how to return both enum and country?
return ???
}
This is just an example to explain what I need (returning one-something, having 2 values, one is string, other is an enum in this case). So, ignore any issues with my string comparison or logic, my point is how to return something. For example, in C#, I could define a struct and return that struct, or I could use out parameters to return 2 values. But I am not sure how to do that elegantly in Java.
I think this is mainly an example of what Jon Skeet has suggested. (edited to include country)
Make your Enum carry the text and the conversion functionality.
public enum AutoMake {
HONDA("Honda", "Japan"),
TOYOTA("Toyota", "Japan"),
VW("Volkswagon", "Germany");
private String country;
private String text;
private AutoMake(String text, String country) {
this.text = text;
}
public static AutoMake getMake(String str){
AutoMake make = null;
AutoMake[] possible = AutoMake.values();
for(AutoMake m : possible){
if(m.getText().equals(str)){
make = m;
break;
}
}
return make;
}
/**
* #return the country
*/
public String getCountry() {
return country;
}
/**
* #return the text
*/
public String getText() {
return text;
}
}
And then store the the make as an enum in the car object
public class Car {
private AutoMake make;
private String model;
public Car() {
}
public Car(AutoMake make, String model) {
super();
this.make = make;
this.model = model;
}
/**
* #return the make
*/
public AutoMake getMake() {
return make;
}
/**
* #return the model
*/
public String getModel() {
return model;
}
/**
* #param make the make to set
*/
public void setMake(AutoMake make) {
this.make = make;
}
/**
* #param model the model to set
*/
public void setModel(String model) {
this.model = model;
}
}
and now you can get both text and enum values from the car object
car.getMake() // Enum
car.getMake.getText() // Text
car.getMake.getCountry // Country
You can convert from text to enum with
Enum make = AutoMake.getMake("Honda");
This would mean AutoMake.getMake(Signal.getAction()) could replace myMethod(signal) with the resulting Enum carrying both make and country.
If you really really want to have tuples in java you can import them from the scala standard lib. As both languages are compiled to the same byte code they can be used together in one project.
import scala.Tuple2;
public class ScalaInJava {
public static Tuple2<String, Integer> tupleFunction(){
return new Tuple2<>("Hello World", 1);
}
public static void main(String[] args) {
System.out.println(tupleFunction()._1());
}
}

How to implement usage dependency, Enumeration data type in Java? Confusion to implement Aggregation, Composition

I have to implement the following class diagram to the java code. This diagram is very complicated and some parts creates confusion. This question definitely going to help me a lot as well as any reader because it contains several important aspects of UML diagram.
class Book{
String isbn;
String publisher;
String publishDate;
int pages;
}
class BookItem extends Book{
String barcode;
boolean isReferenceOnly;
}
class Author{
String name;
String biography;
Collection<Book> book;
}
class Account{
String number;
List<History> history;
String openDate;
AccountState state;
public Account(AccountState state){
this.state = state;
}
}
enum AccountState{
Active,
Frozen,
Closed
}
class Catalog implements Search, Manage{
List<BookItem> bookItem;
/* Implement the methods of Manage interface */
void add(BookItem item){ }
void remove(BookItem item){ }
/* Implement the methods of Search interface */
int search(BookItem item){ }
}
class Account{
String number;
List<History> history;
Student student = new Student();
void setStudent(Student student){
this.student = student;
}
}
interface Search{
int search(BookItem item);
}
interface Manage{
void add(BookItem item);
void remove(BookItem item);
}
class Student{
String name;
String address;
Search searchBook = new Catalog();
}
class Librarian{
String name;
String address;
String position;
Search searchBook = new Catalog();
Manage manage = new Catalog();
Account account = new Account();
void setAccount(Account account){
this.account = account;
}
class Library{
String name;
String Address;
List<BookItem> bookItem = new ArrayList<BookItem>();
Catalog catalog = new catalog();
List<Account> accounts = new ArrayList<Account>();
Library(Catalog catalog){
this.catalog = catalog;
}
void setBookItem(List<BookItem> bookItem){
this.bookItem = bookItem;
}
void setAccounts(List<Account> accounts){
this.accounts = accounts;
}
}
I implemented in the following way but confusion arise in various cases:
How to implement Class Student use the interface Search.
How to implement Class Librarian use the interfaces Search and Manage.
Why we are not use association instead of usage dependency.
How to implement that Enumeration data type in this case with usage dependency [I have just considered AccountState as a class, i the it is a wrong implementation].
How to use AccountState in the Account [I have just created a object of AccountState].
After read many blogs still unable to implement Aggregation and Composition confidently. Note: In this diagram 3 Aggregations and 1 Composition Exist. Those are:
(a) Library consists of many Account. {Aggregation}
(b) Many Book Item is the part of Library. {Aggregation}
(c) An Account is the part of a Student. {Aggregation}
(d) Library must have a Catalog. {Composition}
Please give your valuable advice so i can learn it well. Thanking you.
Since this question is homework for learning purposes, I will post only examples of how to implement the things you need to review and won't give a direct answer about how to apply them to your current design.
Enumeration in Java is implemented by using enum.
enum WeekDays {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
}
Aggregation/Composition means to have a field of the other class. If it's a weak association (aggregation), it should be initialized by the setter or another method. If it's a strong association, it should be initialized in the class constructor since it is needed for the class to live/work.
class WeakAssociation { }
class StrongAssociation { }
class NeedWeekAndStrongAssociation {
private WeakAssociation weakAssociation;
private StrongAssociation strongAssociation;
public NeedWeekAndStrongAssociation(StrongAssociation strongAssociation) {
this.strongAssociation = strongAssociation;
}
public void setWeakAssociation(WeakAssociation weakAssociation) {
this.weakAssociation = weakAssociation;
}
}
Usage dependency means that the class/interface will use the other class/interface within one or more of its methods:
class WantToBeUsed {
public void methodToBeUsed(String data) {
//fancy implementation
}
}
class CannotDoThisAlone {
public void cannotDoItAlone(String data) {
WantToBeUsed wantToBeUsed = new WantToBeUsed();
wantToBeUsed.methodToBeUsed(data);
}
}

Categories

Resources