I'm trying to get to grips with the visitor method in Java.
I'm trying to write a very simple program to get used to it. Basically it is a Food Menu. I want to read in user input (food type (starter, main course...) and the name of the food (pasta, fish...)) and then add this item to the menu.
I'm fairly sure I have the code correct so far, I'm just struggling to figure out how I pass the values read in from the user.
One of my friends who is also a programmer told me that you are supposed to have all of your functionality in the visitor classes (or at least as much as possible).
So do I take the user input and create it into a Menu Element? Then have the visitor add the element to the Menu? (I also want to be able to remove items from the Menu but I'm assuming that this is just reverse engineering the method to add)
Or do I not go so far as to have the visitor actually add the element. For example; would I just create the Menu Element and then pass that, then have the adding functionality in the Menu class?
To me it would make sense to have the visitor actually add the item, as it is functionality I want to keep specific to the adding visitor, but every time I try to implement I keep getting told that I have to make the arraylist containing the Menu Elements static, and I can't help but think I am doing it wrong.
I'm not 100% sure that the Visitor Pattern is correct for what I am trying to do?
Personally I believe I am either really, really close..... or WAY OFF!!
Any help you guys can offer would be great, even if you can point me towards a good tutorial that will help explain how to correctly use this pattern.
Here is what I have so far:
interface MenuElementVisitor {
void visit(Starter starter);
void visit(MainCourse mainCourse);
void visit(Desert desert);
void visit(Drinks drinks);
void visit(Menu menu);
}
Menu Element Classes
interface MenuElement {
void accept(MenuElementVisitor visitor); // MenuElements have to provide accept().
}
class Starter implements MenuElement {
private String name;
public Starter(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void accept(MenuElementVisitor visitor) {
visitor.visit(this);
}
}
class MainCourse implements MenuElement {
private String name;
public MainCourse(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void accept(MenuElementVisitor visitor) {
visitor.visit(this);
}
}
class Desert implements MenuElement {
private String name;
public Desert(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void accept(MenuElementVisitor visitor) {
visitor.visit(this);
}
}
class Drinks implements MenuElement {
private String name;
public Drinks(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void accept(MenuElementVisitor visitor) {
visitor.visit(this);
}
}
The Menu Class
class Menu implements MenuElement {
MenuElement[] elements;
public MenuElement[] getElements() {
return elements.clone(); // Return a copy of the array of references.
}
public Menu() {
this.elements = new MenuElement[] {
new Starter("Soup"),
new Starter("Pate"),
new MainCourse("Steak"),
new MainCourse("Fish"),
new Desert("Ice Cream"),
new Desert("Apple Tart"),
new Drinks("7up"),
new Drinks("Wine"),
};
}
public void accept(MenuElementVisitor visitor) {
for(MenuElement element : this.getElements()) {
element.accept(visitor);
}
visitor.visit(this);
}
}
Visitor to Add Items to the Menu
class MenuElementAddVisitor implements MenuElementVisitor {
System.out.println("Press 1 for Starter, 2 for Main Course, 3 for Desert or 4 for Drinks");
int MenuElementType = Console.readInt();
System.out.println("Type the name of the Menu Element you want to add");
String MenuElementName = Console.readString();
Visitor to Remove Items from the Menu
class MenuElementRemoveVisitor implements MenuElementVisitor {
}
Run the code demo
public class VisitorDemo {
static public void main(String[] args) {
Menu menu = new Menu();
menu.accept(new MenuElementAddVisitor());
menu.accept(new MenuElementRemoveVisitor());
}
}
I think that your "adding" visitor shouldn't know about the fact that you use Command-Line arguments to indicate your menu names.
Indeed, this breaks SRP => Single Responsibility Principle because adding and reading are two actions so two responsibilities. To understand that, imagine you decide to read menu names now from file ... you'll have to open and recode your "adding" visitor class.
You should have a main generic class who just know about String (for the names) and specialized class someone can create or eventually use yours to precise from where arguments are provided.
So in your example, you should try to replace Console.readInt(); and Console.readString() with an int method parameter and a String method parameter.
You may not have a need for a vistor in this case. The gang-of-four says:
" ... Use the Visitor pattern when
an object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes.
many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them.
the classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes. ..."
If you really want a visitor pattern for something similar see this answer.
Related
I created an Athlete class.
public class Athlete {
private final int id;
private final String name;
private final Country sourceCountry;
public Athlete(int id, String name, Country sourceCountry){
this.id = id;
this.name = name;
this.sourceCountry = sourceCountry;
}
}
then I created the following interfaces and sub classes:
public interface IJumper {
public double jump();
}
public interface IRunner {
public double run();
}
public class Runner extends Athlete implements IRunner {
public Runner(int id, String name, Country sourceCountryCode) {
super(id, name, sourceCountryCode);
}
#Override
public double run() {
return Math.random();
}
}
public class Jumper extends Athlete implements IJumper {
public Jumper(int id, String name, Country sourceCountry) {
super(id, name, sourceCountry);
}
#Override
public double jump() {
return Math.random();
}
}
in addition, I created the following RunnerJumper class to create another type of athlete that can both run and jump:
public class RunnerJumper extends Athlete implements IRunner, IJumper {
public RunnerJumper(int id, String name, Country sourceCountry) {
super(id, name, sourceCountry);
}
#Override
public double jump() {
return Math.random();
}
#Override
public double run() {
return Math.random();
}
}
now, I want to create an Team class. the team should be team of runners or jumpers (team of runners can contain Runner & RunnerJumper and team of Jumpers can contain Jumper & RunnerJumper)
so I want the team to be generic..
in addition the team class should have method like "compete" (
something like: forEach Athlete of Team:
run or jump (depends the type of athlete..)
)
how can I achieve this kind of behaviour?
I tried to create it like this:
public class Team<C extends Athlete> {}
but in this form team of runners cannot contain RunnerJumper..
I also tried to create new interface Competitor:
interface Competitor {}
and have both IRunner & IJumper extend it..
this seems good at first:
public class Team<C extends Competitor> {}
but I don't understand how I can Implement the compete functionality in this form...
It's impossible to do it the way you imagine.
Types - in Java - serve to express guarantees. Things that are 100% certain about a piece of code. If a piece of code gets a Duck, there is 100% guarantee that it is also a Bird and an Animal.
But you cannot express relations like "it's either a Duck or a Bucket". You would need both to extend the same supertype and make sure that the type is only extended by these two; in general it would require multiple inheritance and sealed types.
And you cannot express relations which mix values with types, like "if the numberOfLegs == 8, then the type is Octopus". I have no idea how to call the aparatus required for this, but the structural types in Type Script, I think, can express such constraints. I think that duck typing is a prerequisite.
Coming back to Java: if there's a set of objects which can contain Runners or RunnerJumpers, the only thing that you can guarantee in the Java's type system is that all the objects are Runners. No generics, inheritance etc. can change that.
You can use one of the multitude of patterns to achieve your business goal:
refactor the jumping / running behavior into a separate classes, both implementing Action with a single perform method. Then create an interface with a single method: getActions, called, say, a Player. Then, your Team can iterate over Players, get actions for each one and call their perform method in an inner loop. The implementation of the getAction method can even return a static list of lambdas, so that you can access all your player's attributes from inside. This pattern allows you to keep the list of possible actions open (introducing new actions will not require you to recompile or touch your Team class).
if the list of possible actions is statically known by the Team, you can use the Visitor pattern - let the Team call the player's visit method, and the player can call Team's playerJumps(Jumper j) or playerRuns(Runner r).
Or you can use other mechanisms of the language: reflection and casting (this will also make the list of possible actions static).
What you could do is you could create two Team classes, one for the runners and one for the jumpers, like so:
public interface Team {
public void compete();
}
public class TeamRunners implements Team {
private List<Runner> runners;
private List<RunnerJumper> runnerJumpers;
public Team(List<Runner> runners, List<RunnerJumper> runnerJumpers) {
this.runners = runners;
this.runnerJumpers = runnerJumpers;
}
#Override
public void compete() {
for (Runner runner : runners) {
runner.run();
}
for (RunnerJumper runnerJumper : runnerJumpers) {
runnerJumper.run();
runnerJumper.jump();
}
}
}
public class TeamJumpers implements Team {
private List<Jumper> jumpers;
private List<RunnerJumper> runnerJumpers;
public Team(List<Jumper> jumpers, List<RunnerJumper> runnerJumpers) {
this.jumpers = jumpers;
this.runnerJumpers = runnerJumpers;
}
#Override
public void compete() {
for (Jumper jumper : jumpers) {
jumper.jump();
}
for (RunnerJumper runnerJumper : runnerJumpers) {
runnerJumper.run();
runnerJumper.jump();
}
}
}
I have a class like this
public EmployeeRepositoryImpl{
public Employee save(final Employee employee) {
return employeeDao.save(sanitizeEmployee(employee));
}
Employee sanitizeEmployee(Employee employee){
employee.setName(cleanUpBadData(employee.getName());
employee.setPhone(cleanUpBadData(employee.getPhone());
employee.setAddress(cleanUpBadData(employee.getAddress());
......
return employee;
}
private static String cleanUpBadData(String attribute) {
//cleanbaddata here
return attribute;
}
}
I want to refactor this using visitor pattern incase tomorrow we need to add additional logic like cleanup Which I added today.I am not sure I did visitor pattern correctly since I do not have a accept method and Visitable.Can anyone please correct me the right way to do it.
I created
public interface EmployeeVisitor {
void visitEmployee(Employee employee);
}
public class EmployeeVisitorImpl implements EmployeeVisitor {
public void visitEmployee(Employee employee)
{
employee.setName(cleanUpBadData(employee.getName());
employee.setPhone(cleanUpBadData(employee.getPhone());
employee.setAddress(cleanUpBadData(employee.getAddress());
......
return employee;
}
private static String cleanUpBadData(String attribute) {
//cleanbaddata here
return attribute;
}
}
A correct implementation of the visitor pattern would look like this:
interface EmployeeVisitor {
void visitEmployee(Employee employee);
}
class CleanUpEmployee implements EmployeeVisitor {
void visitEmployee(Employee employee) {
...
}
}
class Employee {
void accept(EmployeeVisitor visitor) {
visitor.visitEmployee(this);
}
}
The visitor pattern is specifically designed to separate one or more algorithms from a class structure they operate on. There is no point to the visitor pattern unless there is a class structure you are trying to make your algorithms independent of. In your case you don't seem to have any extensions of Employee so there's really no value to using visitors - just make the algorithms methods of the class.
If your intention is to be able to add additional operations to the class without changing it then there are other patterns that are probably more useful. For example https://en.wikipedia.org/wiki/Strategy_pattern allows the behaviour to be selected at runtime and https://en.wikipedia.org/wiki/Command_pattern allows the behaviour to be encapsulated with its context.
I have some custom classes, which contain information about different viewtypes in a RecyclerView, like title, description, etc (there are different variables for each class though). I want to add these classes to an ArrayList, but I don't want it to be a generic (Object?) ArrayList, I want to make sure only my custom classes can be put in. Now I could do this by making another class for it with a setter and getter, and do some checks, but I'd rather have something like ArrayList<CustomGroup>, where CustomGroup could be any of CustomClass1, CustomClass2, etc... Is this possible, and if so, how would I do this?
Example:
public class CustomClass1 {
String title, description;
int amount;
// Getter & Setter
}
public class CustomClass2 {
String errorMessage;
int errorCode;
// Getter & Setter
}
public class CustomClass3 {
String warningName;
double amount;
// Getter & Setter
}
ArrayList<CustomGroup> arrayList = new ArrayList<>();
CustomClass3 customClass3 = new CustomClass3();
// Set values for customClass3
arrayList.add(customClass3);
CustomClass1 customClass1 = new CustomClass1();
// Set values for customClass1
arrayList.add(customClass1);
I would recommend using an interface for this. You can use interfaces as "tags", where the interface basically defines nothing but the classes you want to allow in the list implement it. In your case, however, you could have the interface define the String and int properties.
Interface "tag" with nothing specified
public interface ICustomClassInterface {
}
public class CustomClass1 implements ICustomClassInterface {
String title, description;
int amount;
}
ArrayList<ICustomClassInterface> arrayList = new ArrayList<ICustomClassInterface>();
Only classes that implement the interface can be added to the list. However, your issue here is you will be getting to them through this interface which defines nothing, i.e. you will need to figure out what type it is.
Ideally you would refactor your classes to have the common functionality either defined in an abstract class or specified in an interface, then you don't need to care what the actual type is.
Interface with needed properties defined
public interface ICustomClassInterface {
String FieldA;
int FieldB;
}
public CustomClass1 implements ICustomClassInterface {
String FieldA;
int FieldB;
}
ArrayList<ICustomClassInterface> arrayList = new ArrayList<ICustomClassInterface>();
I would agree with the other answer which suggests using an interface. I would add that, since the examples that you show do not have the same types, you'll find yourself doing checks; perhaps like:
if (someClass instanceof CustomClass1) {
...
} else if (someClass instanceof CustomClass2) {
...
} else if (someClass instanceof CustomClassN) {
...
} else { ... }
That's not very extensible or easily maintained.
You could use the interface, whether empty or with common attributes of the same type, but it might get ugly though doing said checks. Maybe what you could do to avoid that is add a CustomClassProcessor class which will have overloaded methods for the various types you have to handle; this is called the visitor pattern.
public class CustomClassProcessor {
public void process(CustomClass1 cc) {
// Do stuff for CustomClass1
}
public void process(CustomClass2 cc) {
// Do stuff for CustomClass2
}
public void process(CustomClass cc) {
// Do stuff for CustomClass3
}
...
}
Your interface would be like so:
public interface CustomClass {
public void getProcessed(CustomClassProcessor cp);
}
One example of a concrete custom class would be:
public class CustomClass1 implements CustomClass {
#Override
public void getProcessed(CustomClassProcessor cp) {
cp.process(this);
}
}
And you'd use it like:
for (CustomClass cc : list)
cc.getProcessed(customClassProcessor);
or with Java 8 features...
list.forEach(cc -> cc.getProcessed(customClassProcessor);
You have several absolutely different objects and requirement to join it with array list to show it in recyclerView by position. So you have to use ArrayList of Object's(or another collection of objects) and you can't avoid it and pospone checking types.
You have to create such list and make connection of concrete class of stored object with item type (in getItemType) via using instanceof. After that you can create viewHolders according to these types and then in onBindViewHolder cast current item to connected viewHolder or encapsulate casting in concrete view holders
I've been working on a little inventory system just to practice my OO programming. I am using Java 7 in Netbeans.
The player will have an inventory (ArrayList of base Item Class), all items created will be a child of that base Item class.
No items should be of type BaseItem, they will all extend off of that, so to my understanding, the BaseItem class should be abstract?
public abstract class BaseItem {
protected GoldValue itemValue;
protected String itemName;
//accessors and mutators down here
}
Child item types will also have different properties, which I was going to implement as Interfaces, such as Stackable, Consumable, etc.
The interface looks something like this
public interface Stackable {
public void stack (StackableItem bi1);
}
As you can see, I make a reference to StackableItem here, that is one of the children of BaseItem, which is also abstract and specific items will build out of.
public abstract class StackableItem extends BaseItem implements Stackable{
protected int quantity;
protected int maxStacks;
#Override
public void stack (StackableItem si)
{
if(this.getQuantity() + si.getQuantity() < maxStacks){
this.setQuantity(this.getQuantity()+si.getQuantity());
si.setQuantity(0);
}
else if(this.getQuantity() + si.getQuantity() > maxStacks){
int diff = maxStacks - this.getQuantity();
this.setQuantity(this.getQuantity() + diff);
si.setQuantity(si.getQuantity() - diff);
}
}
}
and here's an example of a specific item:
public class StackableItemExample extends StackableItem{
public StackableItemExample ()throws GoldException
{
this(new GoldValue(0,0,0), "unnamed", 1);
}
public StackableItemExample(GoldValue gv, String name, int quan) throws GoldException
{
this.itemValue = gv;
this.itemName = name;
this.quantity = quan;
this.maxStacks = 10;
this.itemValue.setGoldValue(gv.getGold()*quan, gv.getSilver()*quan, gv.getCopper()*quan);
}
}
My Inventory, being an ArrayList of BaseItem objects, is allowed to have a StackableItemExample object inserted into it no problem. The issue is, my inventory system cannot say BaseItem.stack() since the parent has no knowledge of this method.
I want to make a very easily extendable item system, that a new item can be created with extreme simplicity by implementing and extending pre-created classes and interfaces, but this is getting in my way.
No items should be of type BaseItem, they will all extend off of that, so to my understanding, the BaseItem class should be abstract?
Sounds good to me
If you want BaseItem.stack() to work, you could do at least two things:
Move stack() into your base class, and give it a default implementation of doing nothing. Then override that in your StackableItem class, or
Use instanceof to see whether the BaseItem is a StackableItem, then cast it to a StackableItem and go from there.
The second approach would look like:
BaseItem item = YourList.get(i);
if(item instanceof StackableItem){
StackableItem stackable = (StackableItem)item;
stackable.stack() /* Now works without issue */
}
Make every item Stackable - currently unstackable items should have a stack size of one. You could then get rid of the stackable abstract class and interface, putting that functionality into the base class.
It is more complex than it sounds, but I think I am obliged to try something like it. I want to make an abstract parent class with a prototyping of an enum (I want to declare the enum with only one value probably that will be the default unitialized one and also declaring a couple of methods that I will be using from the subclass), then I want to class that will extend the abstract parent to actually intialize the very same enum (I know that this practically hides the parent enum) so that the kid class will define a set of items inside the enum, but keep the methods probably.
I do not know much about this level of abstraction so I will now describe the nature of my problem, in case there is a more practical solution:
I have a bunch of files that contain classes that implement a lot of commands based on enums. (e.g. class1 implements Observer has an update method that uses an enum-based switch to decide what command was picked, same applies for the other classes) I now want to abstract this whole thing in a way that I have an enum variable with the exact same name in all classes (e.g. CommandSet) so that I can have a generic method inside the parent that will be able to print a help list to my system using the inside methods of the enum. Now I know I can rewrite the exact same method in every class, but I want to abstract it so that others can keep on extending the library I am making!
Hopefully I am not too confusing or too confused and somone can help me! :)
Edit: Here is an idea of the code (Probably not right):
public abstract class Commands{
enum CommandSet{
// empty command, placeholder
null_command ("command name", "command description");
// the Strings used for name and description
private final String name;
private final String description;
// constructor
CommandSet(String name, String description){
this.name=name;
this.description=description;
}
// get parameters
public String getName(){
return name;
}
public String getDescription(){
return description;
}
}
public void showHelp(){
for (CommandSet i : CommandSet.values()) {
printf(i.getName(),":",i.getDescription());
}
}
}
public class StandardCommads extends Commands implements Observer{
// I want to change the enum here, just changing the values so that null_command ("command name", "command description") will get removed and I will add a dozen other values, but keep the methods that the parent had
// update inherited from Observer
#Override
public void update(Observable observable, Object object) {
// I want the commands inside the switch cases defined inside this class's enum
switch(CommandSet.valueOf(String.valueOf(object)){
case command1: doStuff1();break;
case command2: doStuff2();break;
...
case commandN: doStuffN();break;
}
// other methods
void doStuff1(){
...
}
...
void doStuffN(){
...
}
}
public class NonStandardCommads extends Commands implements Observer{
// Another set of commands here for the enum keeping the same methods it had in the parent
// update inherited from Observer
#Override
public void update(Observable observable, Object object) {
// Other set of commands inside this class used in the switch statement
switch(CommandSet.valueOf(String.valueOf(object)){
case Zcommand1: doStuffz1();break;
case Zcommand2: doStuffz2();break;
...
case ZcommandN: doStuffzN();break;
}
// other methods
void doStuffz1(){
...
}
...
void doStuffzN(){
...
}
}
Impossible: Java enums can neither extend another class nor be extended themselves.
They can however implement interfaces. Perhaps you can use that to your advantage.
There is something else about enums that may help you: enums are not immutable. You could change field values of the enums, however that would change them for the whole JVM.
Another approach maybe to pass your subclass instances into a method of the enum and have the enum use your subclass as a call back to get different functionality out of an enum for a different user of the enum.
Nope, you can't do that.
Java Enums run out of gas very quickly & definitely, when you want to add/extend more definitions or instantiate the enum instances, at a later time. (eg load them from database, configure them in an instance method, not just statically.)
Behaviour/ or logic in Java enums is kinda limited too -- you can define & set properties, but only what's statically initializable, and logic seems basic (you end up mainly just comparing references or ordinals, with the other defined enum constants).
What you can do:
You can implement an ancestor Command or AbstractCommand class, with a integer Code, and then subclass it to define concrete values/ additional codes/ load or configure instances, etc.
For further benefit, you get efficient switch & despatch (by Code) plus the ability to define further details/properties, instantiate commands as-needed, etc.
Essentially, this is how you used to define an Enum before Java supported them. Though you may be using them as value objects, rather than strictly static.
My expertise:
I've done extensive compiler & type-system work, tried enums for file-types and associated data/behaviour.. explored the outer limits, and reached the definite boundaries.
I also like being able to instantiate & return a new UnknownFileType("") as an answer, too. Enums can't do that.
Example:
(We'll despatch by String, not int -- since your code appears to be using Java 7. This makes command resolution easier, than requiring both a syntactical "name" and an internal integer "code".)
public static class Command {
protected String code;
protected String desc;
public String getCode() {return code;}
public String getDesc() {return desc;}
public Command (String code, String desc) {
this.code = code;
this.desc = desc;
}
public String toString() {return code;}
}
public class StandardCommands {
public static Command READ = new Command("READ", "read a record");
public static Command CREATE = new Command("WRITE", "create a record");
public static Command EDIT = new Command("WRITE", "modify a record");
}
public class FurtherCommands extends StandardCommands {
public static Command LIST = new Command("LIST", "list all records");
}
public class QueryCommands extends FurtherCommands {
public static class QueryCmd extends Command {
protected String search;
public String getSearch() {return search;}
// constructor..
}
public static QueryCmd QUERY_EXAMPLE = new QueryCmd("QUERY", "example", "query for specified string");
public static QueryCmd createQuery (String search) {
return new QueryCmd( "QUERY", search, "query for specified string");
}
}