Mapping complex data from Model to View - java

Let's consider a simplified MVC architecture, where Model operates on different types of Confections. There are different subtypes of Confection class, such as Candy, Cookie, Doughnut, etc. Every subtype, in turn, has different sets of properties, like size, color, shape and so on.
For instance, that's one implementation of Candy class:
class Candy extends Confections {
public enum Size {
LARGE,
MEDIUM,
SMALL,
}
public enum Color {
RED,
GREEN,
YELLOW,
}
private Size size;
private Color color;
...
}
Now the Model wants to update the View with a new set of Confections to display. Let's say that the only thing View needs to get the picture of a Confection is a string representation of its type and properties, e.g. "candy_red_large". The dumbest thing to do this is to have a number of instanceof branches and switches for types inside the View:
if (confection instanceof Candy) {
result.append("candy");
switch ((Candy) (confection).color) {
case RED:
result.append("_red");
break;
...
}
...
} else ...
Besides this monster is large and ugly, it also doesn't benefit from encapsulation and OOP. Let's consider a better way of doing this by providing each Confection subclass with a method like toString(), which will return the desired string representation:
class Candy extends Confections {
...
public String toString() {
return ("candy_" + size + "_" + color).toLowerCase();
}
}
The only problem I see in this approach is some kind of architectural "trade-off" when Model is actually aware of View implementation details having toString method, which is useless from Model's point of view.
What would be the best approach or design patterns to use in such case for mapping diverse data from Model to View representation?

maybe use some to strings to get what you want:
class Confections {}
class Candy extends Confections {
public enum Size {
LARGE,MEDIUM,SMALL,
}
public enum Color {
RED,GREEN,YELLOW,
}
Candy(Size size,Color color) {
this.color=color;
this.size=size;
}
private Size size;
#Override public String toString() {
return "Candy [size="+size+", color="+color+"]";
}
public String toString2() {
return "candy_"+size+"_"+color;
}
private Color color;
}
public class SO53564342_mapping_complex_data_from_model_to_view {
public static void main(String[] args) {
Candy candy=null;
for(Candy.Size size:Candy.Size.values())
for(Candy.Color color:Candy.Color.values())
System.out.println((candy=new Candy(size,color)).toString()+" "+candy.toString2());
}
}

Idea
I could imagine to introduce a new interface StringRepresentation:
public interface StringRepresentation {
String represent();
}
StringRepresentation will be implemented by Confections. To foce every child of Confections to implement represent make it abstract:
public abstract class Confections implements StringRepresentation {}
After that we have to implement in Candy and the other classes represent. If you want to work with Enums you could let them implement StringRepresentation too.
Example of a String Representation in Candy
public class Candy extends Confections {
private Size size;
private Color color;
public String represent() {
return "candy_" + color.represent() + "_" + size.represent();
}
public enum Size implements StringRepresentation {
LARGE("large"),
MEDIUM("medium"),
SMALL("small");
private final String representation;
Size(String representation) {
this.representation = representation;
}
public String represent() {
return this.representation;
}
}
public enum Color implements StringRepresentation {
RED("red"),
GREEN("green"),
YELLOW("yellow");
private final String representation;
Color(String representation) {
this.representation = representation;
}
public String represent() {
return this.representation;
}
}
}
Benefit
You do not need to use conditions like switch or if and you do not need loops. In addition, each class/component - as above the enums and classes - has its own logic, so you know where to change a representation as you change in the future.

Related

Is it bad practice to return Enums in Java?

Lets say I have a class to model an item in a game like so:
public class Item {
private final EnumItem type;
public Item(EnumItem type) {
this.type = type;
}
public Item(String name) {
this.type = EnumItem.fromName(name);
}
}
public enum EnumItem {
MACHINE_GUN("machine_gun"),
SWORD("sword"),
BAT("bat"),
DEFAULT("default");
private final String name;
public EnumItem(name) {
this.name = name;
}
public String getName() { return name; }
public static EnumItem fromName(String name) {
for(EnumItem i: EnumItem.values()) {
if(i.name.equals(name)) {
return i;
} else {
return EnumItem.DEFAULT;
}
}
}
}
Assume that .equals() and .hashCode() of Item are overridden correctly to compare the internal Enum.
Now I want a way to distinguish these items with a getter in Item: should I return an Enum or the String name? Is it good practice to return an Enum in general? Or is there a better way to distinguish these Items? Because returning the enum kind of looks like exposing the rep to me and I don't want my colleagues to use EnumItem directly to compare Items.
The approaches I thought of are the following:
string getName() to do something like item1.getName().equals("machine_gun");
EnumItem getEnum() to do item1.getEnum().equals(EnumItem.MACHINE_GUN);
item1.equals(new Item("machine_gun"));
static name(String name) { new Item(name) } to do item1.equals(Item.name("machine_gun"));
I don't know what should I do, I'd appreciate some insight from experienced programmers.
I know they look like they would from context, but in my use case these items have no special functionality that would justify extending from the base Item class.
Is this good practice? Sure, you're using aggregation since Item doesn't depend on EnumItem, which is fine. That being said, could it be done better? Sure. Is the alternative I provide the only solution? No.
Alternative
If you want this to be extensible, consider using an interface to represent an item. Then allow the interface to extend this interface to provide some standard types. Alternatively you could use composition or aggregation to define a type inside EnumItem that implements the Item interface to ensure that equals/hashcode for the Item are always override and adhere to some contract.
interface Item {
String key();
}
enum EnumItem implement Item {
private final String key;
EnumItem(String key) {
this.key = key;
}
#Override
public String key() {
return key;
}
}
class AbstractItem implements Item {
// constructor, override name()
}
Item item = EnumItem.FOO_BAR;
Item item2 = new AbstractItem("FooBar");
Item item3 = () -> "FooBar";

Struggling On A Lesson About Classes & Subclasses of CodeHS

I spent two days in class trying to figure it out, but I just don't understand some of the errors.
I actually found a similar question in this site but I still don't get it.
The lesson's name is 4.12.4 Clothing Store.
In this problem, you’ll design a few classes that represent different
pieces of clothing in a clothing store.
You’ll write the classes for TShirt, Jeans, Sweatshirt and Clothing.
The Clothing class should have two instance variables: one for the
size of the clothing (a String), and another for the clothing’s color
(also a string).
Clothing should have two accessor (getter methods) as well:
public String getSize()
public String getColor()
The Sweatshirt class should have a private instance variable (or
field) to store whether or not it has a hood, and a corresponding
getter method
public boolean hasHood()
The TShirt class should have a private field to store the fabric and a
corresponding getter for that called
public String getFabric()
All Jeans should have the color blue.
The constructors should be of this format:
public Clothing(String size, String color)
public TShirt(String size, String color, String fabric)
public Sweatshirt(String size, String color, boolean hasHood)
public Jeans(String size)
And the following is my code:
public class Clothing
{
public String size;
public String color;
public Clothing(String size, String color)
{
this.size = size;
this.color = color;
}
public String getSize()
{
return size;
}
public String getColor()
{
return color;
}
}
public class TShirt extends Clothing
{
private String fabric;
public TShirt(String size, String color, String fabric)
{
super(size, color);
this.fabric = fabric;
}
public String getFabric()
{
return fabric;
}
}
public class Sweatshirt extends Clothing
{
private boolean hasHood;
public Sweatshirt(String size, String color, boolean hasHood)
{
super(size, color);
this.hasHood = hasHood;
}
public boolean getHasHood()
{
return this.hasHood;
}
}
public class Jeans extends Clothing
{
public Jeans(String size)
{
super(size);
}
}
My error:
Errors: Jeans.java: constructor Clothing in class Clothing cannot be
applied to given types;
Grader.java: You may have forgotten to declare hasHood() or it's out
of scope
Jeans passes just one argument to the super constructor. You don't have a one-argument constructor for Clothing. Either make Clothing(String size) or your Jeans class can pass a default value to the super. Like super(size, "Blue") or whatever is appropriate.
EDIT:
Change getHasHood() to hasHood(). Your class is enforcing naming conventions on you.

Interface Segregation Principle

I'm learning SOLID principles with Java and I'm trying to implement two classes with this. My problem is about ISP. I have some methods that is present in one class but not in the other and I also have to refer both classes with the same interface.
This is the first class:
public final class Complex implements Number {
#Override
public String polarForm() {
//This class needs to implement this method
}
#Override
public String rectangularForm() {
//This class needs to implement this method
}
}
Here is the second one:
public final class Real implements Number {
#Override
public String polarForm() {
//This class does not need this method!
}
#Override
public String rectangularForm() {
//This class does not need this method!
}
}
Finally I have to refer to the classes something like this:
public static void main(String[] args) {
Number c = new Complex();
Number r = new Real();
Number n = c.add(r);
System.out.println(c.polarForm());
System.out.println(n);
}
How can I refer to both classes with the same interface without implementing unnecessary methods?
An alternate solution to approach this problem would be to use Composition instead of Inhertiance in conjunction to the interface segregation principle.
Number class
public class Number {
private RectangleForm rectangleForm;
private PolarForm polarForm;
private BigDecimal value;
public Number(RectangleForm rectangleForm, PolarForm polarForm,BigDecimal value) {
this.rectangleForm = rectangleForm;
this.polarForm = polarForm;
this.value = value;
}
public String polarForm() {
return polarForm.transform(this.value);
}
public String rectangleForm() {
return rectangleForm.transform(this.value);
}
//other methods such as add and subtract
}
PolarForm interface
public interface PolarForm {
public String transform(BigDecimal number);
}
RectangularForm interface
public interface RectangleForm {
public String transform(BigDecimal number);
}
RectangleForm implementation for real numbers
public class RectangleFormReal implements RectangleForm {
#Override
public String transform(BigDecimal number) {
String transformed = "";
//transfromed = logic to transform to rectangle form
return transformed;
}
}
PolarForm implementation for Real numbers
public class PolarFormReal implements PolarForm {
#Override
public String transform(BigDecimal number) {
//return the number as is without any transformation
return number.toString();
}
}
Putting the pieces together
public class NumberTest {
public static void main(String[] args) {
RectangleForm rf = new RectangleFormReal();
PolarForm pf = new PolarFormReal();
Number number = new Number(rf, pf,new BigDecimal(10));
String rectangleForm = number.rectangleForm();
String polarForm = number.polarForm();
}
}
You can create the PolarFormComplex and RectangleFormComplex implementations and wire theNumber instance in a similar fashion. The advantage of this approach is that your code will always rely on the interface of the Number class (by interface I mean the public APIs) and you can chose the transformation strategy by injecting the corresponding PolarForm or RectangleForm instances into your Number instance at compile time as shown above or at runtime (via a factory)
Break your Number interface (or base class) into multiple interfaces. The standard operations (add, subtract, etc) are in one; let's say INumber. polarForm and rectangularForm are part of another; let's say IComplex.
Real would implement INumber; Complex would implement INumber and Icomplex. You could then treat both as INumber.
If necessary, you could also create another interface that implements both.

Implementing toString on Java enums

It seems to be possible in Java to write something like this:
private enum TrafficLight {
RED,
GREEN;
public String toString() {
return //what should I return here if I want to return
//"abc" when red and "def" when green?
}
}
Now, I'd like to know if it possible to returnin the toString method "abc" when the enum's value is red and "def" when it's green. Also, is it possible to do like in C#, where you can do this?:
private enum TrafficLight {
RED = 0,
GREEN = 15
...
}
I've tried this but it but I'm getting compiler errors with it.
Thanks
You can do it as follows:
private enum TrafficLight {
// using the constructor defined below
RED("abc"),
GREEN("def");
// Member to hold the name
private String string;
// constructor to set the string
TrafficLight(String name){string = name;}
// the toString just returns the given name
#Override
public String toString() {
return string;
}
}
You can add as many methods and members as you like. I believe you can even add multiple constructors. All constructors must be private.
An enum in Java is basically a class that has a set number of instances.
Ans 1:
enum TrafficLight {
RED,
GREEN;
#Override
public String toString() {
switch(this) {
case RED: return "abc";
case GREEN: return "def";
default: throw new IllegalArgumentException();
}
}
}
Ans 2:
enum TrafficLight {
RED(0),
GREEN(15);
int value;
TrafficLight(int value) { this.value = value; }
}
Also if You need to get lowercase string value of enum ("red", "green") You can do it as follows:
private enum TrafficLight {
RED,
GREEN;
#Override
public String toString() {
return super.toString().toLowerCase();
}
}
I liked this approach for selective alternate toString() if it's useful for anyone out there :
private enum TrafficLight {
RED,
GREEN {
#Override
public String toString() {
return "GREEN-ISH";
}
}
}

one method classes with enum in java

I have an enum that looks like
public enum MyEnum
{
myValue
{
#Override
public String myMethod(String dostuff)
{
return dostuff + "One";
}
},
myOtherValue
{
#Override
public String myMethod(String dostuff)
{
return dostuff + "Two";
}
},
aThirdValue
{
#Override
public String myMethod(String dostuff)
{
return dostuff + "Three";
}
};
public abstract String myMethod(String dostuff);
}
Now I think we can all agree that this looks horrible?
but what would be the bether way? I could have an abstractfactory, but then i would need three implementationclasses that each as a one line method. Dont find that so pretty either. I could use a switch (either in the code or in the enum). But then i could forgett to add a case.
So, whats the way to go? There must be a pattern for this, but cant seem to find one.
The best ive come up with so far is to add comments to autocollapse the methods in Netbeans, not so brilliant that either.
The solution is to create a private constructor for the enum:
public enum MyEnum
{
myValue("One"), myOtherValue("Two"), aThirdValue("Three");
private String value;
private MyEnum(String value) { this.value = value; }
public String myMethod(String dostuff)
{
return dostuff + value;
}
}
[EDIT] Note that you can pass more complex things in. For example, you can pass in a class which implements a certain interface (say Work which has a method doWork()). This way, you can store method calls in enums to do different kinds of work.
Check out the command pattern or maybe the strategy pattern.
It's ugly, but most solutions to non-trivial extensions of the problem are just going to move the ugliness around.
For instance, you could encapsulate the three different behaviors in three different implementations of some interface, and then pass a different behavior implementation to the constructor of each enum. (This is basically the command or strategy approach that others are suggesting).
If you make these implementations, and the interface, separate classes, then you've potentially exposed that behavior beyond the enum, which is unnecessary and arguably ugly.
If you make them private static inner classes of the enum, you've moved the ugliness from the top of the file to the bottom of the file. How much less ugly this is is in the eye of the beholder.
public enum Foo {
ONE(new OneDelegate()),
TWO(new TwoDelegate()),
THREE(new ThreeDelegate());
// ////////////////////
// Private stuff
private final FooDelegate delegate;
private Foo(FooDelegate delegate) {
this.delegate = delegate;
}
// ////////////////////
// Public methods
public String doStuff(String stuff) {
return delegate.doStuff(stuff);
}
// ////////////////////
// Helper classes
private static interface FooDelegate {
String doStuff(String stuff);
}
private static class OneDelegate implements FooDelegate {
#Override
public String doStuff(String stuff) {
return "One " + stuff;
}
}
private static class TwoDelegate implements FooDelegate {
#Override
public String doStuff(String stuff) {
return "Two " + stuff;
}
}
private static class ThreeDelegate implements FooDelegate {
#Override
public String doStuff(String stuff) {
return "Three " + stuff;
}
}
}
The other obvious solution is to put all three behaviors in as private methods, and put a switch(this) in the public method. Personally, I think this is ugly as sin, but a lot of ex-C programmers seem to like it. :)
public enum Foo {
ONE, TWO, THREE;
// ////////////////////
// Public methods
public String doStuff(String stuff) {
switch(this) {
case ONE:
return doStuffOne(stuff);
case TWO:
return doStuffTwo(stuff);
case THREE:
return doStuffThree(stuff);
// If we're handing all enum cases, we shouldn't need
// a default (and per comments below, if we leave out
// the default, we get the advantage that the compiler
// will catch it if we add a new enum value but forget
// to add the corresponding doStuff() handler
// default:
// throw new IllegalStateException("Who am I?");
}
}
// ////////////////////
// Static helpers
private static String doStuffOne(String stuff) {
return "One " + stuff;
}
private static String doStuffTwo(String stuff) {
return "Two " + stuff;
}
private static String doStuffThree(String stuff) {
return "Three " + stuff;
}
}
What about?
public enum MyEnum {
myValue("One"),
myOtherValue("Two"),
aThirdValue("Three");
private final String postfix;
private MyEnum(String postfix) {
this.postfix )= postfix;
}
public String myMethod(String dostuff) {
return dostuff + postfix;
}
}
Even if your real stuff is more complex, there are several techniques that allow such improvements. Please post your real need...

Categories

Resources