Choosing the right classes (from nouns) to build my project - java

The thing is that I've been coding the following exercise and I wanted to ask you something about it:
Develop a system that meets the following requirements:
Create a test generator reminding the following functional requirements:
There are two types of questions: open and multiple choice. The first ones are textual questions that students must develop to respond. The latter are textual questions that have options for students to choose 1. Each question belongs to a topic and each topic is identified by a code and a description.
An exam has N questions and every question has an answer (entered by the student). It is important to identify the student that takes the test and the examiner (the person who assembled the exam).
In order to generate the test, the examiner must indicate the amount of questions you want for each topic. The questions are selected at random from a database of questions. The correction is made in two parts: automatic correction in multiple choice and manual correction in the open questions.
Generated tests should persist and it must be able to create a copy of each exam for each student. The student completes the test, then get the correction automatically, awaiting for manual correction by the examiner. Finally, to complete the correction, the examiner corrects the open questions.
Reports: List of exams and resolutions showing the questions and answers of each exam for each student along with it's note.
I've already coded my program, but the thing is that I have some doubts about choosing the right classes to build my project, because sometimes I can't tell if all nouns from the requirements should be classes or not, or if it just depends on the scope of the system... Reading a couple of books, I've found that we have to select only nouns that have a meaning, and for that reason we usually omit some of them.
The classes I have are the following:
public class Student {
private String name;
// methods
}
public class Exam { // the examiners create the exams
private int id;
private Examiner examiner;
private List<Question> questions = new ArrayList<Question>();
private List<Test> tests = new ArrayList<Test>();
private Map<Topic, Integer> quantityChosenPerTopic = new HashMap<Topic, Integer>();
private Map<Topic, List<Question>> questionsByTopicDisordered;
// methods
}
public class Examiner {
private String name;
// methods
}
public abstract class Question {
private Topic topic;
private String text;
// methods
}
public class OpenQuestion extends Question {
// methods
}
public class MultipleChoiceQuestion extends Question {
private List<String> options = new ArrayList<String>();
private String correct;
// methods
}
public class Test { // the students take the tests
private int number;
private Student student;
private float mark = -1;
private Map<Question, String> answers = new HashMap<Question, String>();
private Map<Question, Boolean> correction = new HashMap<Question, Boolean>();
// methods
}
public class Topic {
private int code;
private String description;
// methods
}
In the previous version of the system, I also had these classes:
public class Option {
private String option;
// methods
}
public abstract class Answer {
// methods
}
public class OpenAnswer extends Answer {
private String text;
// methods
}
public class MultipleChoiceAnswer extends Answer {
private Option option;
// methods
}
A person who helped me with this decided to take out those last classes: Option, Answer, OpenAnswer and MultipleChoiceAnswer. The reason he gave me was that it has not much sense to have them in the program because they just handle one variable and he recommended me to use them as that. And other person told me that it's important that the code works and it should be understandable by other people, plus it's not recommended to have many little classes that don't have almost nothing or very big classes with lots of code. That's why I wanted to ask you that. Thanks.

I would code it so that the resulting classes will have some behaviour, if a class consists only of information then it's better to view it as a data structure.
So, in my opinion, I would not create classes adding properties first, but their methods, by doing so you automatically exclude data structures from classes.
You said
Reading a couple of books, I've found that we have to select only nouns that have a meaning, and for that reason we usually omit some of them
...in my opinion a meaning reflect actions that could be carried out by a class, methods.

Related

What's the best way to DRY Java code ? Creating private method with different Objects for parameters?

I'm creating a RTS game and one of the features is to construct differend kind of buildings. I'm finding a lot of repetition and I was thinking to extract it in helper method, but the problem is that every building is different object which inharits some propertyes from the main building class.
The building methods looks like this:
public static void buildDockyard(Base base) {
if (Validator.checkForBuilding(base, "Dockyard")) {
throw new IllegalStateException("Dockyard is already build");
}
Dockyard dockyard = new Dockyard("Dockyard");
int requiredPower = dockyard.requiredResource("power");
int requiredStardust = dockyard.requiredResource("stardust");
int requiredPopulation = dockyard.requiredResource("population");
Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
dockyard.setCompleteTime(dockyard.requiredResource("time"));
base.getBuildings().add(dockyard);
}
public static void buildHotel(Base base) {
if (Validator.checkForBuilding(base, "Space Hotel")) {
throw new IllegalStateException("Space Hotel is already build");
}
SpaceHotel spaceHotel = new SpaceHotel("Space Hotel");
int requiredPower = spaceHotel.requiredResource("power");
int requiredStardust = spaceHotel.requiredResource("stardust");
int requiredPopulation = spaceHotel.requiredResource("population");
Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
spaceHotel.setCompleteTime(spaceHotel.requiredResource("time"));
base.getBuildings().add(spaceHotel);
base.setCapacity(base.getCapacity() + spaceHotel.getCapacity());
}
I was thinking to refactor like this:
The helper method
private static void construct(Building building, Base base) {
int requiredPower = building.requiredResource("power");
int requiredStardust = building.requiredResource("stardust");
int requiredPopulation = building.requiredResource("population");
Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
building.setCompleteTime(building.requiredResource("time"));
}
Aimed result
public static void buildDockyard(Base base) {
if (Validator.checkForBuilding(base, "Dockyard")) {
throw new IllegalStateException("Dockyard is already build");
}
Dockyard dockyard = new Dockyard("Dockyard");
construct(dockyar, base);
base.getBuildings().add(dockyard);
}
The problem is that each building has unique properties and resource requirements and the main Building class doesn't know about them, so I can't use it as a parameter in the helper method.
All of this is happening in a static helper class for the Base class.
How would you refactor this code ?
Thank you in advance !
Your problems start with using static methods for everything. In an object oriented world you ideally have an object Base and it would have a non-static method addStructure(Struture structure) were Structure is an interface for example. Now you would have objects like Building and Dockyard which would implement Structure.
Implentation of addStructure would be something like this:
if (getBuildings().contains(structure)) {
throw new IllegalStateException(structure.name + " is already build");
}
if (validateStillHaveEnoughResourcesFor(structure)) {
throw new IllegalStateException(structure.name + " can not be added. Not enough resources");
}
getBuildings().add(structure);
Validating structure itself should not be in base. Validating how structure fits to the base should be in the base.
The best way to DRY in Java when making games is to have a clear understanding and terminology of your game. If you read any modern board game manual you will soon see that they will use exactly one word for one concept, like Turn, Round, Building, Player, Resource. This allows to form a rough structure: A Building costs a certain amount of Resource. If a player hasn't enough of Resource then tell him "We need more vespine gas.", etc. The clearer the picture, the DRY-er your Java and easier to create the necessary Classes for your code.
Parameters
If you end up with something like this:
public static void someFunction(Base base, Object param1, Object param2)
public static void someOtherFunc(Base base, Object paramA, Object paramB)
...
Then this is a strong hint that maybe both functions should be part of the Base class.
Enums
If you have a limited set of values then Java Enums can be fantastic to represent them, e.g. your Resource system:
public enum Resource {
POWER, STARDUST, POPULATION
}
Now you don't have to remember if you called it "stardust", "Stardust" or if you even still have a Resource like "stardust". Instead you can use int requiredPower = building.requiredResource(Resource.POWER);
Polymorphism
Let's suppose we have two classes, Building and StarHotel, with StarHotel being a specific kind of Building. Having an abstract class Building allows us to handle some general mechanics in a specific manner, like this:
public abstract class Building {
private ... cost;
private ... requirements;
private ...
// Std-Getter and Setter methods
public ... getCost() { return this.cost; }
}
EVERY Building has a cost, and requirements and other important variables. BUT we handled all the standard stuff of getting and setting these generic variables to a base class from which we now can extend other, more specific buildings. Thanks to the extends keyword you can get the Cost of a StarHotel Object without filling the StarHotel class with repetitive Getters and Setters.
public class StarHotel extends Building {
// Getter, Setter inherited from Building class
}
Interfaces
Java Interfaces allow you to define Interfaces which define methods. In laymen terms: This is useful, because every Class that implements an Interface must implement the method, unless the interface provides the default implementation.
public interface ResourceProvider {
void provideResourceFor(Base base); // A Resource Provider provides Resource for a base.
}
With this interface we have defined that if some Class implements ResourceProvider it has to specify how and what resources to provide for some Base object. Our interface does not care which Resource, which Base and even what provideResourceFor could mean, but as long as something implements ResourceProvider it has to provide the functionality.
Putting all together
Putting Enums, Interface and Polymorphism together, we can now create a StarHotel class that extends Building and implements ResourceProvider, providing 8 Food units and 2 Happiness units to our Base.
public class StarHotel extends Building implements ResourceProvider
public void provideResourceFor(Base base) {
base.addResource(Resource.FOOD, 8);
base.addResource(Resource.HAPPINESS, 2);
}
}
That might be much to take in, but hopefully it will give you a good direction where to look further.

How do i know if a class has a lot of responsability and How do i eliminate this problem

Im doing a project about a restaurant, this restaurants has a lot of products (food) , i have a class Food Combo and this combo is conformed by 1 DRINK, 1 MAIN DISH and 2 EXTRAS. This class has a lot methods and attributes, few of the methods do Mathematical operations and verifications when this should only return a price and bring his additional price
public class FoodCombo {
private ArrayList<Product> list = new ArrayList(); //Each Product has his own price
private boolean refill; //Do you want your drink to have refill?
private boolean supersizing; //
private final double COMBO_DISCOUNT = 0.20;
private final double REFILL_PRICE = 300;
private final double SUPERSIZING_PRICE = 300;
public FoodCombo() {
}
public void addProducto(Product product) {
list.add(product);
}
/* This class needs one Main Dish, two Extras, and One Drink to be considered
as a Food Combo*/
public int countMainDishes() //1
public int countExtras(); //2
public int countDrinks() //3
public boolean isItCombo() {
}
; //Use above methods to verify
//Calculate Methods
public double calculateSubPrice();
public double calculatediscount()
public double calculateRefill();
public double calculateSuperSize();
public double calculateTotal();
public String toString();
//I would aprreciate your suggestion :)
}
Im thinking into separate the responsability of this class into multiple classes so How many clases should i create to accomplish good practices of programming? and what should they do?
First thing is: forget about the implementation. So, "few of the methods do Mathematical operations and verifications when this should only return a price and bring his additional price" does not matter.
If you want to know whether a class is doing too much, write down what the class is for and what it does from a high-level perspective. Then have a look at what you wrote and you will be able to tell whether it is doing too much. Look for whether its responsibility is focused.
For example, if I have a class:
"This class is responsible for interfacing with the NRI G13 Coin Acceptor device, providing an API to accept coins, deal with errors, and report the amount of cash received."
Then even though its implementation may be doing a lot, the class itself is not doing too much.
Alternatively, if I have a class:
"This class reads from the database, processes the data, sends it to another server, and sends a copy to the browser."
Then even though its implementation may be fairly basic (all of these operations usually have one function to call from a library), the class is doing too much because it has responsibility for achieving too many outcomes.

OOP Class Responsibility

I'm developing a hobby project to properly understand encapsulation, what classes can be responsible for, and rules. I asked for a code review and assistance in another forum, but I don't agree with the approach given.
I have the following requirements:
An international student requires documents to complete the registration process, but domestic students don't.
StudentStatus Interface:
public interface StudentStatus {
Collection<String> retrieveDocuments();
StudentType retrieveStatus();
}
public final class Domestic implements StudentStatus {
private final StudentType type;
private final Collection<String> documents;
public Domestic() {
this.type = StudentType.Domestic;
this.documents = Collections.emptyList();
}
#Override
public Collection<String> retrieveDocuments() {
return this.documents;
}
#Override
public StudentType retrieveStatus() {
return type;
}
}
public final class International implements StudentStatus {
private final StudentType type;
private Collection<String> documents;
public International(Collection<String> documents) {
this.type = StudentType.International;
this.documents = Collections.unmodifiableCollection(documents);
}
#Override
public Collection<String> retrieveDocuments() {
return Collections.unmodifiableCollection(documents);
}
#Override
public StudentType retrieveStatus() {
return type;
}
}
Student class:
public final class Student {
//left out constructor and getters for other attributes.
public Collection<String> retrieveDocuments() {
return status.retrieveDocuments();
}
public StudentType retrieveStatus() {
return status.retrieveStatus();
}
public boolean isVerified(StudentType type) {
return this.retrieveStatus() == type;
}
}
University class:
public class University {
private final Map<Student,Collection<String>> registeredStudents;
private final StudentType type;
public University()
{
registeredStudents = new HashMap<Student,Collection<String>>();
type = StudentType.International;
}
public void add(Student student){
if (student.isVerified(type)){
registeredStudents.put(student, student.retrieveDocuments());
}else {
//throw an exception or handle error accordingly
}
}
}
Before I continue, I understand that this is a really over simplified application process. In the real world, a lot more has to happen before a Student can register. The student may have to go through entrance exams, and payment before registration begins. Also, in a realistic environment, this information would probably be stored in a database that the campus employees can access.
In the other forum, the conversation went into what information is being given out, and approaches were given.
Have a rule class, that takes the Student object and verifies that it
is in fact international and has documents.
The problem I have with this, is you're still going to have to ask the Student his/her status either with the retriveStatus() or isVerified(), I don't really see how to do it any other way.
Pass the Student and collection of documents separately to be added to the Map.
In the real world, the University set the rule as stated above and it's responsibility is to check if International students have documentation.
When I suggested the approach above with the add(Student student) they stated it wasn't a good idea because the rules can change, and you'll have to change the Student class as well as the University class.
However, in the real world, a student is well aware of his/her status and if he/she is domestic/international and in possession of documents that can be given to the school.
Given the above approach, is writing the add method this way a good idea? Is there a better approach than the add method?
tl;dr - If a Student has to follow the rules set by the University, how then would the Student object communicate with the University to get the data so that the University can ensure the student object is complying with the rules without breaking encapsulation?
The conversation in previous post was probably leading you in a generally good direction. The principle that applies most is the Open / Closed principle. https://en.wikipedia.org/wiki/Open/closed_principle.
Don't set yourself up to have to constantly modify a particular class or set of classes (in OO world at least) in an area you know is going to be a frequent vector of change. The principle applies equally in the functional world, but your example is using an OOPL.
Little hand-built rules engine is a pretty good solution for your stated problem. Particularly if you know the rule flows on pretty fixed inputs - like the University and the Student. DocumentsRequiredForInternationalStudents is a rule class in that architecture - only needs to change if something about that rule itself changes. New rule, which is going to happen a lot = add new class, not modify existing one.
Sometimes you don't know vector of change, harder to make decisions, but if it's obvious, don't architect a system where you'll have to violate open/closed constantly due to an known change vector.
There are different ways to implement little rules engines. One option (this is crappy pseudo-code so it takes less space)
interface RegistrationRule
boolean isRegistrationValid(Student student) //might need university too for some rules.
class DocumentsNeededForInternationalStudents implements RegistrationRule
boolean isRegistrationValid(Student student)
// return student.status is international and student has documents, or student status is domestic
// (this rule passes through as valid any domestic students).
class RegistrationRules
// (holds all the rules you will use - kind of a factory)
constructor -> add to static list of rules an instance of all your rules
boolean runRulesForStudent(Student)
//iterate through all rules, call isRegistrationValid, short circuit and return false if one of them false
class University
addStudent(Student student)
if (RegistrationRules.runRules(student).... else
That's just one way to throw it together, but you can see it's not really a lot of code. You have an interface, an implementation class for each rule, and a little rules engine class that applies each rule for you. New rule = new class, modify your constructor in the rules engine to add an instance of that class, done.
This pattern begins to struggle a bit when the properties and behavior that are needed in the rules are very diverse and not concentrated in the same small set of classes.
You said:
In the real world, the University set the rule as stated above and
it's responsibility is to check if International students have
documentation.
This means that the verification responsibility lies on University (and can be different for each University) and not the Student. All student can do is provide necessary information for University to verify.
The add method should get documents from retrieveDocuments and run through its rules to determine is student is allowed to be accepted.

How can Extract Class Eclipse IDE refactoring functionality be useful?

I came across a refactoring functionality that looks to be useful as I learn eclipse and java. But I'm not sure how this could be useful. Is there a pattern that would benefit from this kind of refactoring? This refactoring option basically extracted out all variables into another class whose name was changed to append Data at the end.
Any examples of WHAT/WHY this kind of refactoring gives us would be really helpful.
Thank you in advance.
Extract Class is mostly used when a class has too many responsibilities; it is trying to do too much. It splits out the class into two individual classes and then transfers some functionality into the other class - obviously there will be a relationship between the classes because you still want all of the code to interact.
You can combine Extract Class with other refactoring patterns such as Move Method and Move Field that will move methods and fields to the other class in such a way that all of the code still works as intended.
This link has a good example of Extract Class: http://sourcemaking.com/refactoring/extract-class
If you had too many fields in your class and you see that this must be a extra class, you can use it.
Example:
public class Person {
private int age;
private String name;
private String street;
private int streetnumber;
}
to:
public class Person {
private int age;
private String name;
private Adress data = new Adress();
}
public class Address {
public String street;
public int streetnumber;
public Address() {}
}

help with a function

I am trying to add information from main()
to an items class where i am storing the information in a 3 different hashsets
i have 3 classes
project - main()
libaray - addBandMembers function
Item - addband(String... member)
i am adding CD information.
first, i add band, # of songs, title - which works good
Where i am having a problem is adding band members..
I think i need to cast musicCD object to CD class then invoke the
addband function?
Im just not sure how to do that.
Here is the parts of code i think you will need to help me..
this is what i have:
Main()
item = library.addMusicCD("Don't Let Go", "Jerry Garcia Band", 15, "acid rock", "jam bands");
if (item != null) {
library.addBandMembers(item, "Jerry Garcia", "Keith Godcheaux");
library.printItem(out, item);
}
Then, here the first function thats called..
This is where i need help!!!!
public void addBandMembers(Item musicCD, String... members)
{
//musicCD.addband(members); // both cant find addband function..
//Item.addband(members);
}
Then in another class i am trying to add the information..
private String [] members;
public void addband(String... member)
{
this.members = member;
}
oh ya, here is my set..
public class Library
{
private Set<CD> theCDs = new HashSet<CD>();
private Set<DVD> theDVDs = new HashSet<DVD>();
private Set<Book> theBooks = new HashSet<Book>();
So, from the function public void addBandMembers()
i am trying to add members to addband
is my addband function wrong?
I do have a background in C++ and i am trying to apply what i know to java so please be nice. I know i have some more reviewing to do i just cant find what i need on the web..
Thank you..
There appears to be several issues you need to address...
First, in addBandMembers(), if it can't find musicCD.addBand then you either need to define the addBand() method for Item or find the appropriate class that has an addBand() method based on the objects that you can access from Item.
Second, you need to understand the difference between class methods and object methods. Class methods, identified by the "static" keyword, operate on the base class in a way that's shared by all instantiated objects of that class. For example, static foo(x){ this.x = x; } would set the class's static "x" variable, and any access to the "x" variable will use the last set value from calling foo() (assuming no other ways to set x). So, if you have object1 and object2, both of the class that defines foo, object1.x and object2.x would be the same location in memory, both set at the same time when calling foo(). Instance variables, identified by the distinctly missing "static" keyword, are not shared. public bar(y){ this.y = y; } would set a different location in memory for each object of the class - object1.y would be a different memory location, and a (potentially) different value than object2.y.
Third, "Item" is a rather non-descriptive name. Is your library guaranteed to always be for music, or do you need to be more generic? Renaming the class to either LibraryItem or Media (as suggested in another answer) would clarify your code.
Fourth, you didn't provide nearly enough information to really diagnose what's going on. When you ask for help, you should provide relevant output (what gets printed at the end of main?), classes where relevant variables/functions are defined (where are the addband() and addBandMembers() functions defined?) and any error messages (what error do you get when you uncomment either line within addband()?). With complete information, it's much easier for people to help. Without complete information, it's often impossible for people to give really good answers.
Fifth, you talk about casting to Object but mention you don't know how. Casting in Java is very similar to casting in C++ : Foo myFoo = (Foo)myBar;. You'll get a ClassCastException at runtime if myBar is not a subclass of myFoo and myFoo is not a subclass of myBar. Note that you don't need to cast subclasses to their superclasses, as the JVM already knows the class heirarchy, just like the compiler knows in C++. All classes in Java inherit from Object, so there's almost never a need to cast to Object. On the other hand, if you happen to have a subclass of Item where addband() is defined, you can cast item (in main) to the appropriate subclass, and call the addband() method on the casted object.
CompactDisk cd = (CompactDisk)item;
cd.addband(...);
or you can do it as a one-liner as
((CompactDisk)cd).addband(...);
The first one would be useful if you need to use the object as a CompactDisk more than once. The second one would be acceptable if you only need to cast once, maybe twice both next to each other - more than that, creates readability and maintenance problems.
There are a lot of things that don't make sense in this question. Add suggests increasing the number of items in a collection. So addBandMembers should mean you are adding Band members to a band. so I would expect there to be a Band class that contained that method. It should look something like addBandMembers(Set<BandMember> bandMembers) Your addMusicCD is definitley an acceptable way of adding a item to a collection, but requires some value for each parameter, therefore you may want to require just a CD whose constructor can have those specific parameters required.
I would suggest a base class for your media possibly called media that might have a Band property and all other basic properties common to all the types of media. Then you can inherit from the media class in your CD, DVD and Book classes and add specific properties to those media types.
This should get you started.
If by
//musicCD.addband(members); // both cant find addband function..
//Item.addband(members);
You mean that it won't compile then probably the other class where you have
private String [] members;
public void addband(String... member)
{
this.members = member;
}
is not the Item class. That is why musicCd.addband(members) won't work as musicCD is an Item. Item.addband(members) won't work as addband is not a static method.
If I understood correctly the addband method is on your CD class. You should have something like this to make it work.
Note: If you 15 is the CD price, then you should consider using BigDecimal instead of int, double or whatever you are using. If it was something else then change the BigDecimal for and int/double and its corresponding parameter name.
Also, I assumed that the out parameter was a PrintStream
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
Band band = new Band("Jerry Garcia Band");
band.addMember("Jerry Garcia");
band.addMember("Keith Godcheaux");
MusicCD cd = new MusicCD("Don't Let Go", band, new BigDecimal(15),
"acid rock", "jam bands");
Library library = new Library();
library.addMusicCD(cd);
library.printItem(System.out, cd);
}
}
public interface Item {
}
public class Book implements Item {
}
public class DVD implements Item {
}
public abstract class CD implements Item{
private String title;
private BigDecimal price;
private String information;
public CD(String title, BigDecimal price, String information) {
this.title = title;
this.price = price;
this.information = information;
}
}
import java.util.HashSet;
import java.util.Set;
public class Band {
private Set<String> members;
private String name;
public Band(String name) {
this.members = new HashSet<String>();
}
public void addMember(String member) {
members.add(member);
}
}
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Set;
public class Library {
private Set<CD> theCDs = new HashSet<CD>();
private Set<DVD> theDVDs = new HashSet<DVD>();
private Set<Book> theBooks = new HashSet<Book>();
public void addMusicCD(MusicCD cd) {
theCDs.add(cd);
}
public void printItem(PrintStream out, Item item) {
out.print(item);
}
}
I am sure things can be added to this. I tried not change it a lot so you could understand what was needed.

Categories