Suppose I have an abstract class with an abstract builder, both of which get inherited by 3 separate subclasses:
public abstract class Role {
protected string name;
protected int propertyA;
protected int propertyB;
protected abstract static class RoleBuilder<T extends Role, B extends RoleBuilder<T,B>> {
protected T role;
protected B roleBuilder;
protected abstract T getRole();
protected abstract B thisBuilder();
protected RoleBuilder(Hero h) {
role = getRole();
roleBuilder = thisBuilder();
role.name = h.name;
role.propertyA = h.propertyA;
role.propertyB = h.propertyB;
}
public T build() {
return role;
}
}
}
public class Healer extends Role {
int propertyC;
public Healer() {
}
public static final class HealerBuilder extends Role.RoleBuilder<Healer, HealerBuilder> {
#Override protected Healer getRole() {
return new Healer();
}
#Override protected HealerBuilder thisBuilder() {
return this;
}
public HealerBuilder(Hero h) {
super(h);
}
public HealerBuilder setPropertyC(int i) {
role.propertyC = i;
return roleBuilder;
}
}
}
I instantiate the healer class (and the other two subclasses) using enums methods within the enums, like so:
public enum RoleTypes {
BRUISER{
...
},
DAMAGE_DEALER {
...
},
HEALER {
public Healer getRole(Hero h) {
return new Healer.HealerBuilder(h)
.setPropertyC(h.getC);
.build();
}
};
abstract Role getRole(Hero h);
}
Where should I be validating arguments for the creation of these objects?
Within the abstract class constructor (should I validate Hero object properties, or can I assume that object is "safe" if its properties are validated on creation?) and subclass builder methods?
Within the enum methods?
Within the factory method that calls RoleType.getRole(h), used by the rest of my application to actually create objects of type Role?
Related
I have these classes:
enum Brand {
FORD, FERRARI, TESLA, RENAULT;
}
public class Car {
Brand brand;
String plate;
...
}
//getters and setters
Imagine that for some reason, I need to make Car a superclass for two new classes: CombustionCar and ElectricCar. One of the new requierements is that ElectricCar's brand attribute must be always TESLA value and not any of the other ones values.
I've thougth some solutions:
I could keep Brand attr on superclass Car, and make ElectricCar constructor to set TESLA brand. But this way could allow me to set a new Brand after creating the object
public class ElectricCar extends Car {
public ElectricCar(...){
super(Brand.TESLA, ...);
}
ElectricCar ec = new ElectricCar(...);
ec.setBrand(Brand.FORD);
I can take Brand attr out from superclass and set it on both subclasses, but setting it in ElectricCar as a class attribute with a final so anyone would be able to set a new value
public class ElectricCar extends Car {
public static final Brand brand = Brand.TESLA;
...
}
public class CombustionCar extends Car {
private Brand brand;
...
}
Avoid inheritance and use composition, but with this I wont be able to use, for example, a List which contain both:
public class ElectricCar {
private Car car;
private Brand brand = Brand.TESLA;//with no setter
...
}
public class CombustionCar {
private Car car;
private Brand brand;
...
}
I'm asking for the most elegant and manteinable solution, I think any of them would be nice to resolve my problem.
Your first solution is incorrect given that you required a non editable BRAND for an electric car.
Your second solution just doesn't work at all excepted if you override both getter and setter of brand field to use your static field, which is not "elegant and mantainable"
Your third solution doesn't make use of object oriented concept.
A simple solution I would use is to let the field brand and its getter in Car superclass, but I'd only define the setter in the CombustionCar class.
Alternatively, if you extend your model, you could create an intermediate abstract superclass "FreeBrandCar" which implements the setter.
Solution with the setter in CombustionCar
abstract public class Car {
protected String brand;
protected Car(final String b) {
this.brand = b;
}
public String getBrand() {
return this.brand;
}
}
public class ElectricCar extends Car {
public ElectricCar() {
super("Tesla");
}
}
public class CombustionCar extends Car {
public CombustionCar(final String b) {
super(b);
}
public void setBrand(final String b) {
this.brand = b;
}
}
Solution with an intermediate class
abstract public class Car {
protected String brand;
protected Car(final String b) {
this.brand = b;
}
public String getBrand() {
return this.brand;
}
}
abstract public class FreeBrandCar extends Car {
public FreeBrandCar (final String b) {
super(b);
}
public void setBrand(final String b) {
this.brand = b;
}
}
public class ElectricCar extends Car {
public ElectricCar() {
super("Tesla");
}
}
public class CombustionCar extends FreeBrandCar {
public CombustionCar(final String b) {
super(b);
}
}
It respects your requirements :
public void test() {
ElectricCar ec = new ElectricCar();
ec.setBrand("..."): // Doesn't compile
CombustionCar cc = new CombustionCar("Ford"); // OK
cc.setBrand("Fiat"); // OK
Arrays.asList(ec, cc)
.stream()
.forEach(car -> System.out.println(car.getBrand())); // prints Tesla and Fiat
}
I am having two java class as below,
public class Class1{
private Object actionObject;
public Object getActionObject() {
return actionObject;
}
public void setActionObject(Object actionObject) {
this.actionObject = actionObject;
}
}
Second class
public class Class2 {
private Long id;
private int idver;
private int valueDate;
}
There are two statement as below,
Class1 deserializedValue = (Class1) event.getDeserializedValue();
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
I want to mock the second statement
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
how can i do this?
For testing purposes you can use a strategy pattern. You just need an interface or an abstract class with two different implementations. One of them is the mock implementation, something like this:
public interface EventStrategy {
// More methods...
boolean isAssignableFrom(final Object object);
}
public class MyEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return Class2.class.isAssignableFrom(object.getClass());
}
}
public class MockEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return true;
}
}
I have a Scala + Java project.
In the java classes I needed 2 classes that extend from the same class, and their usage is defined in scala.
So I have this class
public class BaseUser {
int id;
private String name;
public BaseUser withName(String name){
this.name = name;
return this;
}
}
and the extended class
public SpecificUser extends BaseUser {
//inherit default for now
}
Then in scala I have a definition of a DAO
trait BaseUserDao {
def insertUser(user:BaseUser) : Boolean
}
class SpecificUserDao extends UserDao{
def insertUser(user : SpecificUser) : Boolean = {
db.insert(user).isDefined
}
}
But this does not compile, it says that i have to implement insertUser(user:BaseUser) instead of SpecificUser
How do I define it so that i can create an implementation per user type ?
Change your implementation to something as shown below. Have a type parameter T whose upper bound is BaseUser. In the declaration of SpecificUserDao just make the T SpecificUser.
trait BaseUserDao[T <: BaseUser] {
def insertUser(user: T) : Boolean
}
class SpecificUserDao[SpecificUser] extends BaseUserDao[SpecificUser] {
override def insertUser(user: SpecificUser): Boolean = ???
}
Or you can declare the type T inside the trait.
trait BaseUserDao {
type T <: BaseUser
def insertUser(user: T) : Boolean
}
class SpecificUserDao extends BaseUserDao {
override type T = SpecificUser
override def insertUser(user: SpecificUser): Boolean = ???
}
Your constructor should be written like this:
public class BaseUser {
protected int id;
protected String name;
public BaseUser(String name){
this.name = name;
}
}
I'd like to create an abstract super class, called Unit and give it a number of protected static fields, such as name, health, attackPower etc.
public abstract class Unit {
protected static String name;
protected static int maxHealth;
protected static int atkPower;
public String getName() {
return name;
}
}
I'd then like to create several subclasses, such as Soldier, Wizard and Tank, and statically allocate the protected field in each of the classes, so that all Soldiers have the same field values, all Wizards have the same field values, and all Tanks have the same field values. I tried something like this:
public class Soldier extends Unit {
static {
name = "Soldier";
maxHealth = 80;
atkPower = 15;
}
}
public class Wizard extends Unit {
static {
name = "Wizard";
maxHealth = 60;
atkPower = 25;
}
}
If I create a Wizard object, wizard, and then call wizard.getName() I get "Wizard". However if I then create a Soldier object, soldier, calling wizard.getName() returns "Soldier" instead. The soldier object statically overwrote the values of the variables in the wizard and soldier classes.
Wizard wizard = new Wizard();
wizard.getName(); //Wizard
Soldier soldier = new Soldier();
wizard.getName(); //Soldier
Is there any way to do what I want to do, that is keep different static values for the same variable in each subclass?
The proper way is IMHO to make getName() (same for health etc) abstract:
public abstract class Unit {
public abstract String getName();
}
and
public class Wizard extends Unit {
private static final String NAME = "Wizard";
#Override
public String getName() {
return NAME;
}
}
Don't make the members static. Make abstract methods that subclasses have to override for each of these fields. This way you also restrict access to fields that shouldn't be set again, and are only accessed in a get context:
public abstract class Unit {
public void battleCry() {
System.out.println("RAWR! I am a " + name() +
"! Tremble at my " + atkPower() +
" attack points!");
}
public abstract String name();
public abstract int maxHealth();
public abstract int atkPower();
}
And then subclasses override these:
public class Wizard extends Unit {
protected final String name = "Wizard";
#Override
public String name() {
return name;
}
#Override
public int maxHealth() {
return 60;
}
#Override
public int atkPower() {
return 25;
}
}
This makes it easier for further subclasses to override these methods as well:
public class BossWizard extends Wizard {
#Override
public String name() {
return "Boss" + super.name();
}
#Override
public int maxHealth() {
return super.maxHealth() * 2;
}
#Override
public int atkPower() {
return super.atkPower() * 2;
}
public void specialAtk() {
// Something special for the BossWizard
}
}
You can see now if you have an instance of Wizard and BossWizard respectively, the battlecry is different:
wizardInstance.battleCry(); // RAWR! I am a Wizard! Tremble at my 60 attack points!
bosswizardInstance.battleCry(); // RAWR! I am a BossWizard! Tremble at my 120 attack points!
I'm trying to prepare an interface i want to implement for Datamodel-Classes.Therefor i want to use an enum inside the interface so i know i need to implement it later.
Example:
public interface MyModelInterface {
public enum Field;
public Object get(Field field);
public void set(Field field, Object value);
}
The expected implementation:
public class MyModel implements MyModelInterface {
public enum Field {
ID("id"),
Name1("Name1"),
Name2("Name2");
private String field;
private Field(String field) {
this.field = field;
}
}
public Object get(Field field) {
//...
}
public void set(Field field, Object value){
//...
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get(MyModel.Field.ID));
System.out.println(myModel.get(MyModel.Field.Name1));
}
}
Since I don't know which fields the model will contain until I implement it.
I did some research and figured that enum can't be extended, so i am aware of that.
is there any way to archive this or any kind of workaround?
i don't want to use String Parameters on the getter/setter Methods to avoid using wrong values.
Thanks in advance for any suggestion.
Update:
So this is what worked for me: Splitting the interface/class in three parts, including an abstract class:
Interface:
public interface MyModelInterface<E extends Enum<E>> {
public Object get(E field);
public void set(E field, Object value);
}
Abstract Class:
public abstract class MyAbstractModel<E extends Enum<E>> implements MyModelInterface<E>{
protected final EnumMap<E, Object> fields;
public MyAbstractModel(Class<E> enumKlazz) {
fields = new EnumMap<>(enumKlazz);
}
#Override
public Object get(E field) {
return fields.get(field);
}
#Override
public void set(E field, Object value) {
this.fields.put(field, value);
}
}
Class(where i actually archive my goal):
public class MyModel extends MyAbstractModel<MyModel.Field> {
public MyModel() {
super(MyModel.Field.class);
}
public enum Field {
ID("ID"),
Name1("NAME1"),
Name2("NAME2"),
Age("AGE"),
;
private final String field;
private Field(String field) {
this.field = field;
}
public String getName() {
return field;
}
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get(Field.Name1));
}
}
Interface fields are static and final implicitly.
What you could do is to have an interface method returning Enum<?>, and your classes implementing it.
For instance:
interface Foo {
public Enum<?> getEnum();
}
class Bar implements Foo {
enum Blah {
INSTANCE;
}
public Enum<?> getEnum() {
return Blah.INSTANCE;
}
}
Edit
Not completely sure I understand your question update, but here's a solution that will de-couple returning a specific enum instance from an enum, by means of two interfaces.
The example is self-contained in a Main class.
public class Main {
public static void main(String[] args) {
System.out.println(new Bar().getEnumField().name());
}
static interface IHasEnum {
public Enum<? extends IMyEnum> getEnumField();
}
static interface IMyEnum {
public Enum<? extends IMyEnum> getField();
}
static class Bar implements IHasEnum {
enum Blah implements IMyEnum {
DEFAULT_INSTANCE,
THE_FIELD;
public Enum<? extends IMyEnum> getField() {
return THE_FIELD;
}
}
public Enum<? extends IMyEnum> getEnumField() {
return Blah.DEFAULT_INSTANCE.getField();
}
}
}
Output
THE_FIELD
Note
The trick here is to add a "default" instance to the enum (DEFAULT_INSTANCE), so the getField method is an instance method, hence overriding the one declared in the IMyEnum interface.
Again, not entirely sure this addresses your issue.
What you are describing is an EnumMap<E, T> - which functions like an array, with that same get-
public class MyModelBase<E extends Enum<E>> {
private final Class<E> enumKlazz;
private final EnumMap<E, Object> fields;
public MyModelBase(Class<E> enumKlazz) {
this.enumKlazz = enumKlazz;
fields = new EnumMpa<>(enumKlazz);
}
public Object get(E field) {
return fields.get(field);
}
public void set(E field, Object value) {
fields.put(field, value);
}
}
enum UserField { id, surname, name, age };
MyModelBase<UserField> userModel = new MyModelBase<>(UserField.class);
userModel.set(UserField.surname, "X");
Because of type erasure the enum map needs the class. Above the enum class is also stored as field, as some static Enum methods need the enum class. For iterating, and so on.
Java generics will be the best solution.
Lets assume, you don't know the contents of the Field as mentioned.
Create a generic interface like this:
public interface MyModelInterface<T> {
public T get();
}
Then create a class Field like this:
public class Field {
private String id;
private String name1;
private String name2;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
}
and then your model class will look like
public class MyModel implements MyModelInterface<Field> {
#Override
public Field get() {
Field field = new Field();
field.setId("ID");
field.setName1("Name1");
field.setName2("Name2");
return field;
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get().getId());
System.out.println(myModel.get().getName1());
System.out.println(myModel.get().getName2());
}
}