I have a Register class contains 8 sets& gets methods
using:
public class Register {
public Register(String Username) {
JFrame myFrame = new JFrame();
}
public void setUname() {
JoptionPane.showInputDialog(myFrame, "Enter Username");
}
public String getUname() {
return Uname;
}
}
There are other methods, 8 in total all requiring user input as String or double.
How in another class, can I import the methods into an ArrayList?
public class RegisterApp {
public addUser() {
ArrayList<Register> MyReg = new Arraylist<Register>();
myReg.add(Class Register);
}
}
Uncertain really of what goes after myReg.add
You need to add a reference to a Register.
public class RegisterApp {
public addUser() {
ArrayList<Register> MyReg = new Arraylist<Register>();
//Make an instance of Register and add it to the list
myReg.add(new Register("Me"));
}
}
You also mention adding methods to the list. What do you mean by that? What else are you trying to do? Do you want to call those methods on the instances in the list? You can do that like this:
for (Register reg : myReg) {
System.out.println(reg.getUname());
}
Note:
Your set method doesn't actually save the value anywhere. You are not storing the result in uname (which should be lowecase u). In general, setters are written so they are passed the new value in. This way you are not tied to using an input dialog anytime you change the name. That is a UI decision and should not effect the data model.
public void setUname(String uname) {
this.usname = uname;
}
Related
I'm having a problem with inheritance. I've illustrated it with those account classes :
class Account {
accountLevel = BASIC;
connect() {...}
changePassword() { ... }
ChangeEmail() { ... }
}
class CustomerAccount extends Account {
accountLevel = CUSTOMER;
createOrder() { ... }
payOrder() { ... }
}
class AdminAccount extends Account {
accountLevel = ADMIN;
addProduct() { ... }
deleteProduct() { ... }
}
If I have an instance of an Account and I want to cast it to a AdminAccount to do addProduct() is it okay to do that :
Account account = new AdminAccount();
if(account.accountLevel == ADMIN){
AdminAccount adminAccount = (AdminAccount) account;
adminAccount.addProduct();
}
Edit:
I want to have all my accounts in the same List, because they all use the same connect method. But when the account is connected I still have an account object but I want to use their dynamic type methods, so i'm forced to cast the object.
It's almost like an instanceof but with extra steps. I feel like having to cast the account isn't very OOP, is there another more elegant solution ? Maybe not use inheritance between the accounts classes ?
One way to approach this is:
AdminAccount account = new AdminAccount();
account.addProduct();
If the expectation is only an Admin Account can add a product, relevant methods should expect an Admin Account in the input instead of an account. Is there a reason the instance is being created as an Account instead of an Admin Account?
Edit - Including sample packaging type handling into a manager class.
public static void main(String args[])
{
AccountManager manager = new AccountManager();
manager.addAccount(new User());
manager.addAccount(new User());
manager.addAccount(new Admin());
System.out.println(manager.getUsers().collect(Collectors.toList()));
}
public static final class AccountManager
{
private final List<Account> allAccounts = new ArrayList<>();
public Stream<User> getUsers(){ return getAccountType(User.class); }
public Stream<Admin> getAdmins(){ return getAccountType(Admin.class); }
public Stream<Account> getAccounts(){ return getAccountType(Account.class); }
public <T extends Account> void addAccount(T account) { if(account.connect()) allAccounts.add(account); }
#SuppressWarnings("unchecked") private <T> Stream<T> getAccountType(Class<T> type){ return allAccounts.stream().filter(type::isInstance).map(act -> (T) act); }
}
public static final class User extends Account{}
public static final class Admin extends Account{}
public static class Account { boolean connect(){ return true; } }
In general, it's considered not to be a good practice to have if statements by some type attribute or by instanceof checks.
An alternative to this is the visitor pattern. Here's a sketch of what you could do:
interface IAccount {
void process(AccountProcessor processor);
}
interface AccountProcessor {
void processBasicAccount(Account acc);
void processCustomerAccount(CustomerAccount acc);
void processAdminAccount(AdminAccount acc);
}
The idea is that you have an interface that defines a process method for all the accounts, that receives an AccountProcessor (you can change the names here, this is just to show an example). There should be one method for every different type of account. You could even use method overloading, i.e. all methods could be named something like processAccount and receive a specialized account type.
Now, your Account class and all its subtypes should implement the IAccount interface:
class Account implements IAccount {
#Override
void process(AccountProcessor processor) {
processor.processBasicAccount(this);
}
// all the other Account stuff
}
class CustomerAccount implements IAccount {
#Override
void process(AccountProcessor processor) {
processor.processCustomerAccount(this);
}
// all the other CustomerAccount stuff
}
class AdminAccount implements IAccount {
#Override
void process(AccountProcessor processor) {
processor.processAdminAccount(this);
}
// all the other AdminAccount stuff
}
Now, with all these pieces in place, you are ready to process your list of accounts:
class AccountProcessorImpl implements AccountProcessor {
private List<Account> accounts; // filled with all the accounts
void doSomethingWithAllTheAccounts() {
// iterate all the accounts and process each one of them
accounts.forEach(IAccount::process);
}
#Override
public void processBasicAccount(Account acc) {
// do something with the basic account
}
#Override
public void processCustomerAccount(CustomerAccount acc) {
// do something with the customer account
}
#Override
public void processAdminAccount(AdminAccount acc) {
// do something with the admin account
}
}
I hope you grasp the general idea. This is just a sketch to show you the core technique. There might be variants, i.e. you might have separate processors for each different type of account, or you might process the list of accounts in a class other than the AccountProcessorImpl, etc.
It's really OK. We call it polymorphism in OOP. Parents can be cast to all children.
I'm working on a small project where I want to have a list of a class called "DevelopmentEmployee", but only one of them is allowed to manipulate certain methods in another class "Project". The way I have implemented it, the class Project has a field called projectLeader, which is of the type DevelopmentEmployee. When a DevelopmentEmployee attempts to access methods in the class Project, I want to check if the DevelopmentEmployee is equal to the specific instance of Project's projectLeader.
Something like
public class Project {
private DevelopmentEmployee projectLeader;
private List < Activity > activities = new ArrayList < Activity > ();
public Project(DevelopmentEmployee pL) {
this.projectLeader = pL;
}
public void addActivity(String activityName) {
if (projectLeader.equals(DevelopmentEmployee * ) {
activities.add(activity);
}
}
}
But I can't figure out a way to make the access requirement work. How can the instance of the class Project know who is trying to access it?
You should also pass the DevelopementEmployee in addActivity for checking it against the projectLeader.
public void addActivity(String activityName,DevelopmentEmployee employee) {
if (projectLeader.equals(employee) {
activities.add(activity);
}
}
Then you need to override equals method in DevelopmentEmployee class, for proper checking of equality, like the one as shown below :
public boolean equals(DevelopementEmployee e){
if(e!=null && this.employeeId==e.employeeId)
return true;
else
return false;
}
Several possibilities come to mind:
Provide the instance of the one accassing the project method to the method:
public void addActivity(String activityName, DevelpmentEmployee user) {
if (projectLeader.equals(user)) {`
Create some class that holds information about active user and use that inside the methods:
public class Project {
private UserRegistry userRegistry;
private List<Activity> activities = new ArrayList<Activity>();
public Project(UserRegistry userRegistry) {
this.userRegistry = userRegistry;
}
public void addActivity(String activityName) {
if (userRegistry.isActiveUserProjectLeader()) {
activities.add(activity);
}
}
}
public class UserRegistry {
private DevelpmentEmployee projectLeader;
private DevelpmentEmployee activeUser;
private List<DevelpmentEmployee> user;
public void addUser(DevelpmentEmployee user) { ... }
public void makeProjectLeader(DevelpmentEmployee newLeader) { ... }
public void makeActiveUser(DevelpmentEmployee newActiveUser) { ... }
public boolean isActiveUserProjectLeader() { ... }
}`
My question is more of a design issue than anything else. I'm currently developing a classic Server-Client chat program in Java. Everything is fine until I get to the commands. I thought it would be convenient for users to send commands that would then be treated by the server for changing their nickname for example. The thing is I want to make flexible code and above all, object-oriented code. To avoid endless if/else if statements to know what command was typed I believe it would be better to create a class for each command which inherit from a superclass Command. Then I could return the specific command through a getCommand() function overriden in all subclasses. But it does not solve my problem at all. The server still needs to test with instanceof what command has been returned. One way to do it dynamically would be to sort of auto downcasting it from the superclass Command and then call the appropriate function in the server class. For example:
public void processCommand(CommandNick c) {}
public void processCommand(CommandKick c) {}
But I haven't found any proper way of doing that and even if I did, I feel like there's still a design issue here. And I am convinced there is a nice and flexible way to do it but days weren't enough for me to figure it out. Any ideas? Thanks in advance! :)
I assume your server receives the message as an Object with a Sender and a String. Create your Command classes, and in the server init code, make a HashMap<String, AbstractCommand> with a String as key and your AbstractCommand class as value. Your commands should extend this class. Register all your commands, like so:
commandRegistry.put("help", new HelpCommandHandler());
I assume a command is a message with a ! before it. So when you receive a message, check if it is a command:
Message message = (Your Message)
String messageBody = message.getBody();
Sender messageSender = message.getSender();
if(messageBody.startsWith("!")) {
// Split the message after every space
String[] commandParts = messageBody.split(" ");
// The first element is the command base, like: !help
String baseCommand = commandParts[0];
// Remove the first character from the base, turns !help into help
baseCommand = baseCommand.substring(1, baseCommand.length());
// Creates a new array for the arguments. The length is smaller, because we won't copy the command base
String[] args = new String[commandParts.length - 1];
// Copy the elements of the commandParts array from index 1 into args from index 0
if(args.length > 0) {
System.arraycopy(commandParts, 1, args, 0, commandParts.length - 1);
}
// Your parse method
processCommand(sender, baseCommand, args);
}
public void processCommand(Sender sender, String base, String[] args) {
if(commandRegistry.containsKey(base)) {
commandRegistry.get(base).execute(sender, args);
} else {
// Handle unknown command
}
}
public abstract class AbstractCommand {
public abstract void execute(Sender sender, String[] args);
}
Sample implementation. I assume your server is a Singleton, and you can get on Object of it with Server.get() or any similar method.
public class HelpCommandHandler extends AbstractCommand { /* !help */
#Override
public void execute(Sender sender, String[] args) {
sender.sendMessage("You asked for help."); // Your code might not work like this.
}
}
public class ChangeNickCommandHandler extends AbstractCommand { /* !changenick newNick */
#Override
public void execute(Sender sender, String[] args) {
// I assume you have a List with connected players in your Server class
String username = sender.getUsername(); // Your code might not work like this
Server server = Server.get(); // Get Server instance
server.getUsers().get(username).setNickname(args[0]); // Argument 0. Check if it even exists.
}
}
// Server class. If it isn't singleton, you can make it one like this:
public class Server {
private static Server self;
public static Server init(/* Your args you'd use in a constructor */) { self = new Server(); return get(); }
public static Server get() { return self; }
private List<User> users = new List<User>();
private HashMap<String, AbstractCommand> commandRegitry = new HashMap<>();
// Make construcor private, use init() instead.
private Server() {
commandRegistry.put("help", new HelpCommandHandler());
commandRegistry.put("changenick", new ChangeNickCommandHandler());
}
// Getters
public List<User> getUsers() {
return users;
}
public HashMap<String, AbstractCommand> getRegistry() {
return commandRegistry;
}
}
This is a bit of pseudo code to illustrate that your controller doesn't need to know about the command processors (no need for instanceof).
abstract class CommandProcessor {
/* return boolean if this Command processed the request */
public static boolean processCommand(String command, User user, Properties chatProperties, Chat chat);
}
/* Handle anything */
public class CommandRemainder extends CommandProcessor {
#Override
public static boolean processCommand(String command, User user, Properties chatProperties, Chat chat) {
chat.appendText("[" + user.getName() + "] " + command);
return true;
}
}
/* Handle color changing */
public class CommandColorizer extends CommandProcessor {
protected static List<String> ALLOWED_COLORS = new ArrayList<>(Arrays.asList("red", "blue", "green"));
#Override
public static boolean processCommand(String command, User user, Properties chatProperties, Chat chat) {
if ("fg:".equals(command.trim().substring(0,3)) {
String color = command.trim().substring(3).trim();
if (ALLOWED_COLORS.contains(color)) {
chat.setForeground(color);
}
return true;
}
return false;
}
}
public class ChatController {
protected Chat chat = new Chat();
protected User user = getUser();
protected Properties chatProperties = getChatProperties();
protected List<CommandProcessor> commandProcessors = getCommandProcessors();
{
chat.addChatListener(new ChatListener(){
#Override
public void userChatted(String userChatString) {
for (CommandProcessor processor : commandProcessors) {
if (processor.processCommand(userChatString, user, chatProperties, chat)) {
break;
}
}
}
});
}
List<CommandProcessor> getCommandProcessors() {
List<CommandProcessor> commandProcessors = new ArrayList<>();
commandProcessors.add(new CommandColorizer());
commandProcessors.add(new CommandRemainder()); // needs to be last
return commandProcessors;
}
}
I am getting an IndexOutOfBoundsException whenever I try to use the userNames list from the MainApp class. I am, however, certain that the names are added to the list from the ServerController class, so I don't understand why the list is empty when called in another class.
I suppose this may be a problem of instantiation from checking similar problems on SO, which I have being trying to solve for quite some time but I am simply unable to do so. I would really appreciate any suggestions, TIA.
Here is my user class whose sole purpose is to store user data, i.e. names and IDs.
public class User {
public User() {
}
public ArrayList<String> userNames = new ArrayList<>();
public ArrayList<String> getUserNames() {
return this.userNames;
}
}
Here is my server class: Adding the names to the userNames list is working alright.
public class ServerController {
private final Server server;
private final User user;
private final GameConfig gameConfig;
public ServerController(GameConfig gameConfig) {
this.gameConfig = gameConfig;
this.server = new Server();
this.user = new User();
}
public User getUser() {
return user;
}
private class ServerListener extends Listener {
//this is where I add the names to the userNames list
#Override
public void received(Connection connection, Object obj) {
server.sendToAllExceptTCP(connection.getID(), obj);
if (obj instanceof String) {
final String jp = (String) obj;
user.userNames.add(jp);
}
}
Here is my MainApp: I try to access the names of the users stored in userNames. The names are added to the list by the ServerController whenever a connection is received which works fine, but I get the exception in the createPlayer method.
public class MainApp {
public User user = new User();
public Game createPlayer(){
if (("Mitspieler".equals(client1)) && ("Mitspieler".equals(client2)) && ("Mitspieler".equals(bot1))) {
for (int i = 0; i < clients.length; i++) {
//this is the source of the exception
players[i + 1] = createHumanPlayer(user.getUserNames().get(i), i, restColors[i]);
}
}
//....
}
The stacktrace:
Exception in thread "JavaFX Application Thread"
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at client.MainApp.createPlayer(MainApp.java:265)
You create two instances.
public class MainApp {
public User user = new User(); // Instance 1
}
public class ServerController {
private User user;
public ServerController(GameConfig gameConfig) {
this.user = new User(); // Instance 2
...
}
}
Instance 1 and Instance 2 do not share any data. Instance 1 holds your added names, Instance 2 does not.
If you do not plan on having multiple instances of your controllers you could do something like
public class User {
private static User USER;
public static User getInstance() {
if(null == USER) {
USER = new User();
}
return USER;
}
}
public class MainApp {
public Game createPlayer() {
User user = User.getInstance();
List<String> userNames = user.getUserNames();
}
}
User would then be a Singleton. But be aware: if you have multiple instances of ServerController all will use the same list of users. If that is not what you want you need to initialize ServerController and MainApp with the same instance of User.
You create a User object in two places. In the ServerController you create and successfully add usernames to the array. Then in the MainApp you create a User object and it never has any userNames in it.
Basically, i have a class where i have my arrays in, which is like this
public final class DepotDatabase {
private Driver[] arrayDrivers;
public DepotDatabase() {
arrayDrivers = new Driver[4];
arrayDrivers[0] = new Driver(1234, 1234, 0); // sample driver
arrayDrivers[1] = new Driver(4444, 4444, 0); // sample driver
arrayDrivers[2] = new Driver(1337, 1337, 1); // sample manager
arrayDrivers[3] = new Driver(1234, 1234, 0); // sample driver
}
and i want to print this array in another class, i did set up the array in another class
public Driver(int username, int password, int managerCheck) {
this.username = username;
this.password = password;
this.managerCheck = managerCheck;
}
but now i want to be able to print out all the drivers, but in another class which will be called ViewDrivers or something similar
You can create a method inside DepotDatabase to print the array, then create an object from and call print method.
public final class DepotDatabase {
private Driver[] arrayDrivers;
public void printArray() {
for (int i = 0; i < arrayDrivers.length; i++) {
Driver d = arrayDrivers[i];
System.out.println("Username : " + d.getUsername());
System.out.println("Password : " + d.getPassword());
System.out.println(" Manager Check: " + d.getManagerCheck());
}
}
the from the test class you can do:
public void execute() {
DepotDatabase ddb = new DepotDatabase();
ddb.printArray();
}
That's why you'll need to have getters and setters. You should have:
public Driver[] getDrivers() {
return arrayDrivers;
}
and in the other class, you simply call it (and print it or whatever).
Read this tutorial.
If you plan to print your array in another class you show create an accessor to it.
The common pattern for Java is to use "get plus name off attribute", getDrivers() you should also avoid the class name in such geter as it may changed due to application life.
public final class DepotDatabase {
//your code
public Driver[] getDrivers() {
return this.arrayDrivers;
}
}
Next question to answer is a returning the whole array is good idea. When you return it as above you loose control on it. And every one that call that method will be able to change the content of it.
To prevent this you should use so called Defensive copying
public Driver[] getDrivers() {
return Arrays.copyOf(arrayDrivers, arrayDrivers.length);
}
Then person will get an copy of it an will not harm your class.
The issue with this is that consumer of your class will have to call this method every time to get fresh list of cars.
To solve this issue you may want to user the [collection framework] where instead of array you cold define:
List<Driver> drivers new ArrayList<>();
and provide the drivers as [immutable] list
public Iterable<Driver> getDrivers() {
return java.util.Collections.unmodifiableList(drivers);
}
Iterable is an interface, that allow you to obtain an interator the the list consumer of class wold have possibility to traverse it. IF you wan to allow him to check that list contains some driver you can set the return type as Collection
class Storage {
private String items[] = new String[10];
public String[] getItems() {
return Arrays.copyOf(items, items.length);
}
}
class Store {
Storage storage = new Storage();
private void printStorage() {
String[] items = storage.getItems();
for (String item : items) {
}
}
}