I'm a C.S.S.E. undergrad student and I'm facing some issues in Java MVC design related to a student program management application. I have to display some auto-generated (random number I guess) on the student ID textfield.
The StudentAddView.java do not display and return the random number on the TextField.
public class StudentAddView extends View{
private JTextField studentNumberField = new JTextField("", SIZE);
}
public StudentAddView(Model StudentList, Controller StudentController){
super(StudentList,StudentController);
add(studentNumberField);
}
Then for the student.java under model, it contains the methods.
public class Student{
public int studentNumber;
the constructor under student.java
public void setstudentNumber(int studentNumber)//setter {
Random random = new Random();
studentNumber = random.nextInt(1000);
this.studentNumber = studentNumber;
}
public int getstudentNumber()//getter{
return studentNumber;}
Lastly, the stringbuffer inside the student.java
public String StringBuffer (String str){
str = "student[";
str = str+"student number"= +studentNumber+","; }
or is it because I have to create a class to return the random number and store as a data to return the value inside a textfield?
You're supposed to update your registered view(s) after changing a value in the model, i advise you to use a model observer and interfaces as it will make things clearer for real cases in the future.
I strongly advise you to read some example of application of this pattern before trying to use it. It will make it way easier to implement and visualize its purpose and pros. However i won't do it here, as smarter and better people have already done it elsewhere, just google it. (here is a practical example for starters https://www.tutorialspoint.com/design_pattern/mvc_pattern.htm)
Good luck in the great world of patterns !
Related
I don't have idea how to add to array enum. I made constructor using fields with enum and its works, but I don't know how to make it in constructor without field. I hope that you understand what Im thinking about. In my code I comment where I think i have problem.
I've got:
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
System.out.println("name of producer:");
String producername = Main.sc.nextLine();
System.out.println("name of model:");
String modelname = Main.sc.nextLine();
System.out.println("ram:");
int ram = Main.sc.nextInt();
System.out.println("cpu:");
String cpu = Main.sc.nextLine();
cpu = Main.sc.nextLine();
System.out.println("components:");
System.out.println("how many components do you want to add?");
int z = Main.sc.nextInt();
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = //<-- how to add enum in array?
}
setProducerName(producername);
setModelName(modelname);
setRam(ram);
setCpu(cpu);
setComponents(com);
}
My constructor using field is like that and it works.
public Laptop(String ProducerName, String ModelName, int Ram, String Cpu, Components... components) {
super();
this.ProducerName= ProducerName;
this.ModelName= ModelName;
this.Ram= Ram;
this.Cpu= Cpu;
this.components= new Components[components.length];
this.components= Arrays.copyOf(components, components.length);
}
Please help.
You could get the enum value by its name.
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
...
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = Components.valueOf(Main.sc.nextLine());
}
...
}
I'm not 100% clear what you're asking, but you can get an array filled with your enum constants from the enum itself: Components.values() will return an array of all the enum constants. It will essentially return:
new Components[]{Components.WIFI, Components.BLUETOOTH,
Components.CAMERA, Components.SSD}
Side recommendation: don't use Scanner inside of your Laptop constructor, and in fact, get all user interface code out of all constructors and instance methods of that class. All user interface code belongs elsewhere.
is there any other way of applying this table to array rather than creating 31 of them?
The layout looks like:
state_name|year|crimetype1|crimetype2|place|count|
row1: state1|2001|murder|knife|home|5|
row2: state1|2001|murder|axe|home|2|
row3: state2|2001|robbery|baseball|shop|1|
and so on for 31 different states.
I thought of creating 31 arrays for each state with 5 rows but is there any other way of making it simpler?
Simply put: objects. That way, you will not have to have nested arrays.
Make a class:
public class Crime{
private int year;
private String state;
private String crimeType1, crimeType2;
private String place;
private int count;
//And then you'd have some useful stuff here...
}
Besides this, I don't think you should combine the 31 values anymore - they are 31 separate, independent occurrences.
First, create a Crime object which can represent a single row in that collection. Let's make it naturally comparable against itself based on the state.
public class Crime implements Comparable<Crime> {
private String state;
private Year year;
private String crimeType1;
private String crimeType2;
private String place;
private int count;
public int compareTo(Crime other) {
return state.compareTo(other.state);
}
}
I leave the construction of this object as an exercise for the reader.
Next, you'll want to add the results of that value to a list.
List<Crime> crimes = new ArrayList<>();
// In a loop reading the file
crimes.add(crime);
At this point your work is pretty much done; if you want to get the crimes by a specific state, you can use the Stream API to filter based on that.
It is better to create class Crime as follows
getHeader() returns header and getRow will return the row . (or toString)
public class Crime {
String stateName;
String year;
//...
public static String getHeader(){
//you can improve this
return "state_name|year|crimetype1|crimetype2|place|count|";
}
public String getRow(){
return stateName + "|" + year +"|" ...
}
public static void main(String[] args) {
List<Crime> state = new ArrayList<>(31);
//or
List<Crime> state = Arrays.asList(new Crime[] {
new Crime("ST","2004",..),...
});
}
}
as KevinO pointed if you are coding OO language it is good to think in OO way otherwise there no point of using java.
Create a Crime class with all the values except state and then a Map
Map<String,ArrayList<Crime>> multiMap = new HashMap<String,ArrayList<Crime>>();
Here String is state name and the ArrayList for all the crimes in that state, So at the end there will be 31 keys (Here we are using state as unique keys) in muliMap Object.
So later you no need to filter statewise crimes, all you need to do is
ArrayList<Crime> state1Crimes = multiMap.get("state1");
Simple and straight forward.
So i'm working on this project and i'm having trouble moving variables from one class to the other. The goal of this tiny software is to have the user input 2 pieces of information, one's a string and the other is an int. I also have 2 classes, one to retrieve the information and the other one to calculate it.
This is the first class called Software:
import java.util.Scanner;
public class Software
{
public Scanner softwareName;
public Scanner devicesAmount;
public Software()
{
devicesAmount = new Scanner(System.in);
softwareName = new Scanner(System.in);
}
/**
*Gets the information from the user to later on process
*/
public void InfoGet()
{
Devices findDevices= new Devices();
Devices findNumber= new Devices();
String softwareName;
int devicesAmount;
Scanner sc= new Scanner(System.in);
System.out.println("Welcome to the Software License Calculator");
System.out.println("Please type in the name of the Software:");
softwareName = sc.nextLine();
System.out.println("");
System.out.println("Please type in the number of devices that have the software:");
devicesAmount=sc.nextInt();
findDevices.Calculations(devicesAmount);
findNumber.getNewDevices();
sc.close();
System.out.println(softwareName+ " & "+ findNumber);
}
}
And here's the second class called Devices:
public class Devices
{
public int NewDevices;
public String softwareName;
/**
* Gets number of Devices to preform the calculations of removing 1000 users
*/
public static void Devices()
{
Software getDevices= new Software();
getDevices.InfoGet();
}
public void Calculations(int devicesAmount){
if (devicesAmount>=1000){
NewDevices= devicesAmount - 1000;
}
else{
NewDevices=devicesAmount;
}
}
}
dunno why I post as user when I'm on my movil device, but to the point:
First of all in the class Software you have 2 objects "Device", following the MVC arquitecture you should only declare 1 controller object for the view class, to start I recommend you to only declare 1 Device for Software class, like this and we're gonna make the variables protected just cause they should be private or protected to respect the encapsulation:
public class Software {
protected Devices devices;
protected Scanner softwareName;
protected Scanner devicesAmount;
... }
I recommend you to do the same for the Devices class variables.
Then we're gonna build a proper constructor for Devices class so we can move the values through classes:
public Devices (String softwareName) {
this.softwareName = softwareName;
this.newDevices = 0;
}
So we can have this values at the Devices class. Then we need to add the getter for newDevices and adding the toString method to the Devices class so you can print the object.
public int getNewDevices() {
return newDevices;
}
public String toString() {
return softwareName + " & " + newDevices;
}
Then we're gonna move some stuff at the Software InfoGet method to build de devices correctly and printing it.
public void InfoGet() {
String softwareName;
int devicesAmount;
Scanner sc= new Scanner(System.in);
System.out.println("Welcome to the Software License Calculator");
System.out.println("Please type in the name of the Software:");
softwareName = sc.nextLine();
System.out.println("");
System.out.println("Please type in the number of devices that have the software:");
devicesAmount=sc.nextInt();
devices = new Devices(softwareName); // So we initialize the object.
devices.Calculations(devicesAmount);
sc.close();
System.out.println(devices.toString()); // Here we just call the toString() method we build to print the values.
}
We didn't use the getNewDevices() method, but building getters and setters for controller classes is a good practice in general ;).
I highly recommend you to read about MVC (model-view-controller) if you wanna build your proyect in a "standar" way.
To solve your problem you can add to each class the getters and setters for each variable you need to move so you can move values between classes.
Like this for setters:
public void setValue(Object value) {
this.value = value;
}
And this for getters:
public Object getValue() {
return this.value;
}
It's very confusing between Scanner, Device, Software, classes and objects with the same name upper or lower cases.
I should recommend to rename you classes and variable clearly.
Some further advices:
why keeping Scanner as variables ? It's not data, it media to get it.
why note keeping data ? like softwareName (Scanner AND String).
I would
add two variables (softwarename and amount), private
keep them
add methods to Set and Get
Calculations() (and others) won't compile. Probably you need to add an argument to that method and you are done (?):
public void Calculations(int devices2){
...
The purpose of the program is to calculate the volumes of different geometrical figures (Like a cylinder or a pyramid). I've started out by adding a list where the user can choose between the different figures.
The problem is that I don't know how to make the program know which formula to use. I need to be able to separate the choices instead of just making an int out of the answer.
private void btnAktiveraActionPerformed(java.awt.event.ActionEvent evt) {
String form = listForm.getSelectedValue().toString();
int fo = Integer.valueOf( form );
String höjd = txfHöjd.getText().toString();
int hö = Integer.valueOf( höjd );
String bredd = txfBredd.getText().toString();
int br = Integer.valueOf( bredd );
String radie = txfRadie.getText();
int ra = Integer.valueOf(radie);
String djup = txfDjup.getText();
int dj = Integer.valueOf(djup);
double ACyl = 3.14*ra*ra*hö;
double APyr = (br*dj*hö)/2;
double AKub = br*dj*hö;
double ARät = br*dj*hö;
txfHöjd.setEnabled(false);
txfBredd.setEnabled(false);
txfDjup.setEnabled(false);
txfRadie.setEnabled(false);
listForm.setEnabled(false);
}
private void btnBeräknaActionPerformed(java.awt.event.ActionEvent evt) {
// I know this code won't work, its just a reminder.
if (answer == Cyinder){
System.out.print("volymen är: "+ACyl+" cm^3");
}
}
I don't understand your question very clearly. I would suggest to make a plan to solve your problems.
make a list of figures that program will calculate
make a list of methods to count volumes of those figures
create individual classes, variables etc...
create methods
create main method with user input
You mentioned you don't know which formula to use. I assume there won't be many formulas in your program. I would create an individual method for each individual figure i.e. piramidFormula(), cilinderFormula()...
There is no point to refer to polimorphism when I think your level of programming is very basic at this stage.
I hope that will help you a little bit.
You need a list to hold the things, you seem to understand this just fine.
You need a way to select things. Selection is typically not exactly the same thing as the list, you need a class to be responsible for the "selection" behaviour.
Each thing has a routine that can calculate the volume. That means it will need input parameters. This is where it starts to get tricky, because if you want all of your things to be in the same list, you need to decide how to manage the different input parameters for the different types in the list.
public List<VolumeCalculations> volumeCalculations ...
public interface VolumeCalculation {
public double getVolume();
}
public class CubleCalcuation implements VolumeCalculation {
private double side = 0;
public void setSide(double value) {
this.side = value;
}
#Override
public double getVolume() {
return side*side*side;
}
}
the other volume calculations are left as an exercise to you.
Then you need to put them all in the list
volumeCalculations.add(new CubeVolumeCalculation());
...
But when you select the calculation, you will need "something" to ask for the right input.
public interface CalculationInputGather {
public void setCalcualtion(VolumeCalcuation value);
public void askForInputs();
}
which the one for the CubleCalcuation might look like
public CubeInputGather implements CalculationInputGatherer {
#Override
public void setCalculation(VolumeCalcualtion value) {
if (value instanceof CubeCalcuation) {
this.volume = value;
}
throw new IllegalArgumentException("value must be a CubeCalculation");
}
public void askForInputs() {
System.out.println("enter the side value:");
// read the value
volume.setSide(value);
}
}
then when you know the selected item in the list, you can use a Map of Calcuations to their input gatherers to lookup the right input gatherer for the selected calcuation.
If you already have the list for the user to choose from, maybe consider a map instead. You can have all your shapes as the keys of the map and then the formulas for volume as the values of the map. The list of shapes can be provided to the user via the keySet and their response can be matched back against the map to find the formula.
EDIT: You have your formulas for each shape inside an action event. You'll need to move those into a separate class
public static class Formulas() {
// list all formulas here
private String cylinder = "3.14*r*r*h";
}
Then when you hit the action you can either create a new instance of the Formulas class and use any convenience methods you might write in there.
Hey I am new java so forgive me if what I am about to ask is obvious, but I will try to explain as best as I can.
Its just a project that has been set for university so its not in a serious manner.
I have a class called MarsRoom which holds the attributes say for all the dimensions of the room like the totalheight and width of the walls in order to calculate the heat loss that the room will suffer in order to adjust the amount of solar energy that is needed to keep the room at the room temperature set.
The problem I am having is what is better practice or solution, to pass the attributes of the size of the room in a constructor(but this could get quite long in size, as the ones below are not only the ones that I may need) or create a whole different class specifically for that room like ROOM TYPE U? and set the attributes in there.
As it stands I can create a whole new room just by instantiating the room with the new values, but its going to get a little long, whereas I would rather not create a whole new class for a different room which may only differ from another room by a few meters on one of the walls!.
So what I am really trying to get at it, is is it ok to pass that many attributes to the constructor on instantiation?
//the instantiation in the runnable
MarsRoom room1 = new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
//the constructor in the MarsRoom class
public MarsRoom(String roomname, int windowsH, int windowsW, int wallsH, int wallsW, int windowC, int heaters, int lights){
name = roomname;
TotalWindowHeight = windowsH;
TotalWindowWidth = windowsW;
TotalWallHeight = wallsH;
TotalWallWidth = wallsW;
windowCeiling = windowC;
numheaters = heaters;
numlights = lights;
roomheaters = new Heaters[numheaters];
}
I'd say that you should be adding factory methods here.
Basically, keep your constructor, but add methods like
static Room createLaundryRoom(laundryRoomParameters) {
return new Room(...laundry room parameters plus defaults
common to all laundry rooms...);
}
One of the great benefits object oriented programming is the possibility of not repeating yourself in code. Hence objects, which define data (members) and functionality (methods), and no requirement to create instances of these "prototypes" with hard values until run-time. To create a new class for each room when it
may only differ from another room by a few meters on one of the walls
would be to deny OOP (and Java) by gross repetition. I'd stick with the constructors, and if similar kinds of rooms end up emerging, try one of the static factory methods suggested, or break up common functionality using inheritanceOracle.
Create a map with the keys being
Map<String, Integer> map = new HashMap();
map.put("TotalWindowHeight", new Integer(10));
map.put("TotalWindowWidth", new Integer(5));
...
map.put("NumberOfHeaters", new Integer(3));
MarsRoom room1 = new MarsRoom("RoomU", map);
Constructor will be like:
public MarsRoom(String roomname, HashMap<String, Integer> params) {
name = roomname;
TotalWindowHeight = map.get("TotalWindowHeight").intValue();
TotalWindowWidth = map.get("TotalWindowWidth").intValue;
...
roomheaters = new Heaters[map.get("NumberOfHeaters").intValue()];
}
this is not good OO however, but it seems like you are looking for something quick. If you want good OO you need to create an object for Window and in it you have hieght and width, another for ceiling, and you should not have number of something as a field, you should have an array to store the heater objects, and so and so forth, but this is quick and meets your requirement.
While technically legal, constructors with very long argument lists may be inconvenient to use. It also depends on whether you this the list may grow in the future or in subclasses.
If you have many parameters, but they have defaults and sometimes only a few need to be changed, you may find the Builder pattern useful. The idea is to replace constructor arguments with function calls, and allow them to be chained, for example:
public MarsRoom() {
//empty or just basic stuff set here
}
public MarsRoom setTotalWindowHeight(int TotalWindowHeight) {
this.TotalWindowHeight = TotalWindowHeight;
return this;
}
public MarsRoom setTotalWindowWidth(int TotalWindowWidth) {
this.TotalWindowWidth = TotalWindowWidth;
return this;
}
...
then, you can call:
MarsRoom room1 = new MarsRoom()
.setTotalWindowHeight(20)
.setTotalWindowWidth(40);
Of course, if you wanted to set all parameters this way, it's longer (thou maybe more readable) than the single constructor. But if you only set 2 parameters out of 10, it will usually be more convenient.
You don't show what the fields of MarsRoom are, but for each feature, I would have a Collection of sub-objects. A MarsRoom has-a List of Windows. A MarsRoom has-a List of Walls. etc... Then have setters and getters for each and methods to add new instances of these features.
Since this is for school, I'm only including a little bit of pseudo code.
public class MarsWindow {
int height;
int length;
// Setters & Getters
// standard getters & setters go here
int getArea() {
return this.height * this.width;
}
}
public class MarsRoom {
List<MarsWindow> windows;
List<MarsWall> walls;
List<MarsLight> lights;
List<MarsHeater> heaters;
public List<MarsWindow> addWindow(MarsWindow window) {
// Add a window to the "windows" list here
}
public List<MarsWall> addWall(MarsWall wall) {
// Add a wall to the "walls" list here
}
// Do this for the other fields
int getTotalWindowArea() {
int area = 0;
// Iterate over all windows
for(MarsWindow window : windows) {
area += window.getArea();
}
return area;
}
// Add other calculation methods here
}
If what you're trying to do is simply not duplicate the parameters you're passing the constructor, you can simply put them in a separate static method, like so:
public static MarsRoom newRoomU() {
return new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
}
You could also use some polymorphism or have different types of rooms or something similar to this and then have a superclass with the common values that all rooms will have.
You can also have more than one constructor and have different ones for values you wish to set depending on the room type etc.
Its always better to work with objects rather than primitives, you could use factory to create objects.
//the constructor in the MarsRoom class
public MarsRoom(String roomname, WindowDimension windowDimension, WallsDimensions wallDimension, RoomAmbience ambience){
}
public class WindowDimension{
private int height; //int windowsH
private int width; //int windowsW
private int circumference; //assumed windowC is circumference
}
public class WallsDimension{
private int height; //int wallsH
private int width; //int wallsW
}
public class RoomAmbience{
private int heaters;
private int lights;
}