How to design class hierarchy? - java

I'm programming in Java 7 and now I need to create a base class BaseCondition for all concrete Conditions. What do I mean is that I have some types: Date, Integer, and some enums and I need to store conditions like _ALL_INTEGERS > 100 and < 200, _ALL_INTEGERS > 100, _ALL_INTEGERS < 200 and so for Dates (more, less, between). For enums I'm going to chose only one value now, so If
enum BonusType{
BIRTHDAY,
REGISTRATION
}
then the conditions will look like BonusType= BIRTHDAY and BonusType= REGISTRATION.
So what I was trying to write was
public class <T> ConditionBase{
private T low;
private T high;
//GET, SET
}
and used low=high when I would need to create a condition for enum. All conditions would be a derived class as follows:
public class DateCondition extends BaseCondition<Date>{ }
public class BonusTypeCondition extends BaseCondition<BonusType>{ }
Example of a concrete condition:
BaseCondition c = new BonusTypeCondition();
c.setLow(BonusType.BIRTHDAY);
c.setHigh(BonusType.BIRTHDAY);
QUESTION: I'm not sure about if won't get into troubles when I try to extend some functionality (adding more complicated conditions). Couldn't you suggest something more scalable?

Well, your concept is very close to storing a Java 8 Lambda/closure on each case. If you can't switch versions, you have to abstract the fact that low or 'high` might not be reasonable for Enums. So your true base for condition should be like this:
public interface ConditionBase<T>
{
boolean fulfills(T object); // True if this object fullfills the condition.
}
That is the only general case. You can then create some implementations for classes with upper bounds.
public class<T extends Comparable> LessThanX() implements ConditionBase<T>
{
...
private T value;
...
public boolean fullfills(T object)
{
return object.compareTo(value) < 0;
}
}
Forgive me if there are any syntax errors there, my Java is rusty since I moved to Scala.
You can define as many type of conditions as you want, with one or more internal values (between for isntance). You can also create some wrappers that contain several conditions inside them and check the object against all of them, etc.

Related

Two lists of different custom types to be passed in the same method as an argument

I have two Classes like this:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class FooCounts {
private Long countOfRows;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class DooCounts {
private Long countOfRows;
}
I created two Lists of the above types and did the following:
List<FooCounts> fooCounts = ...; //initialisation doesn't matter
List<DooCounts> dooCounts = ...;
Long countOfRows = 0L;
if(!fooCounts.isEmpty){
countOfRows = fooCounts.map(FooCounts::getCountOfRows).sum().longValue();
}
if(!dooCounts.isEmpty){
countOfRows = dooCounts.map(DooCounts::getCountOfRows).sum().longValue();
}
Is it possible to make these two 'if' blocks as one 'if' block by creating a method out of it? I mean something like this:
private Long fooDooCounts(List<T> fooDooCounts) {
if(!fooDooCounts.isEmpty){
countOfRows = fooDooCounts.map(fooDooCounts::getCountOfRows).sum().longValue();
}
Java is strictly namespaced. The name of a method/field are relevant only insofar as that they exist in the context of a type (hence, in java you can't define fields or methods outside of a type - because names do not mean anything outside of them), and the name of a type is only meaningful in light of the package it is in.
In other words, the actual name of string's toLowerCase method is java.lang.String::toLowerCase.
There is no way in java to say 'I want to call the toLowerCase method on this object, whatever the type of the object is, regardless of where the method comes from. Long as it is called toLowerCase, call it'. It just doesn't exist. You can see this in action in class files, where any invocation is necessarily always bound up with a fully qualified name (it would look like java/lang/String toLowerCase()Ljava/lang/String; in classfile-ese, but it's the same principle, just in classfile form).
There's a good reason for this.
Imagine these two types:
interface Gun {
void shoot(Person p);
}
interface Camera {
void shoot(Person p);
}
hopefully this illustrates the subtle but serious dangers of allowing you to write, in a programming language 'just call shoot(p) on this object, whatever it might be, if it has a shoot method, go for it'.
Hence, 'can you write code in java that fetches a field of a given name, regardless of what type the objects are, as long as it has a field of some name, just get the data out of it' - the answer is a very very simple: No, you can't, and you don't want to - that is not how java is designed to work, and going against the 'grain' of how a language wants to be used results in all sorts of maintenance headaches.
Fortunately, it also gives you the strategy to fix the problem: Ensure that the 'fetch operation' is the same fully qualified name. How do we do that? By introducing a type that unifies the definition of what countOfRows means, and then have your various classes implement it:
interface RowCounter {
long countRows();
}
Now we have a uniform definition. You can stick docs on this if you want. Then it is simply a matter of implementing it in your types:
class FooCount implements RowCounter {
#Override public long countRows() {
return countOfRows;
}
}
Because now the countRows method in your FooCount class is in fact just a more specific implementation of RowCounter::countRows, the fully qualified name of that method is com.pkg.RowCounter::countRows. Thus, you can now invoke it:
long sum(List<? extends RowCounter> rowCounters) {
long totalCount = 0;
for (var r : rowCounters) totalCount += rowCounters.countRows();
return totalCount;
}
and you can pass a list of FooCounter objects, or a list of BarCounter, or a list of RowCounter, etc.

Using a comparable on 3 different classes

I'm trying to implement a function that returns the maximum object of a given Comparable (generic) list.
I have 3 classes that I have implemented their compareTo method that returns the 1 if this is bigger than other, -1 if this is smaller than other, and 0 if they're equal.
Now my problem is with understanding with how do I work with a generic input COmparable list.
Here's the signature of my function, and the code I wrote so far (that refuses to work on me):
public static Comparable<?> getMax(List<Comparable<?>> ls) {
LinkedList<Comparable<?>> tmpComp = new LinkedList<Comparable<?>>();
for (Comparable<?> c : ls)
tmpComp.add(c);
Comparable<?> maxObj = tmpComp.get(0);
for (Comparable<?> c : tmpComp)
if (c.compareTo(maxObj) > 0)
m = c;
return m;
}
I'm writing a system that has users in it, and ads. Users and ads both classes that have "profit" field on them that all I do in my compareTo methods is to compare which of the two (this, or other) have more profit and then just returns the right value according to that. The 3rd class is compared via another field, which is an int as well, that indicates the level (int) of the Quest.
Also that if statement, specifically, gives me an error of the type "is not applicable for the arguments".
Any clues?
Thanks in advance!
Reading your comment, I suggest you redesign your model to be:
interface ProfitGenerating {
double getProfit();
}
class User implements ProfitGenerating {
...
}
class Advert implements ProfitGenerating {
...
}
List<ProfitGenerating> profits = ...;
Optional<ProfitGenerating> maxProfit = profits.stream()
.max(Comparator.comparingDouble(ProfitGenerating::getProfit));
The answer by Mạnh Quyết Nguyễn is good. But it does not account for the situation where you have multiple potential types T, which appears to be your situation.
So in that situation, just wrap your various classes with a single class and use his solution.
If you have a User class and an Ad class, then create a wrapper like so:
class ProfitMaker implements Comparable<ProfitMaker> {
User user;
Ad ad;
public int compare(ProfitMaker p) {
//check my profit and compare with profit of p
}
}
Use that class as the "T" when usign the getMax from Mạnh Quyết Nguyễn.
Alternatively, use an interface
interface ProfitMaker extends Comparable<ProfitMaker> {
int getProfit();
}
Make both your User and Ad classes implement that interface, and that use that interface as the "T" along with the getMax method from Mạnh Quyết Nguyễn.
Your three classes must be comparable to each other. For this they will need to implement Comparable<SomeX> where SomeX is their lowest common superclass. In the worst case, SomeX is Object.
If this is the case, you can simply do:
ls.stream().max(Comparator.naturalOrder())
Alternatively, instead of forcing your classes to implement Comparable<...>, you could capture comparison semantics in a Comparator<...> and then do:
ls.stream().max(comparator)
Using a comparator is better for cases where the order is not really "natural" for the type or where there may be different orders. I think this is the case here since you actually compare instances of different types. It is hard to argue that some order is "natural" for these instances as they don't even belong to one type.
If you compare your instances based on some property they share (like int getProfit()), it would make sense creating a common interface like Profitable. Then you could do:
ls.stream().max(Comparator.comparintInt(Profitable::getProfit))
Note that if you compare on privitive types, you should use comparingInt/comparingLong/comparingDouble instead of comparing to avoid unnecessary boxing and unboxing.
If you for some reason can't create and implement a common interface like Profitable, you can still use comparingInt and likes. You'll just have a much uglier lambda:
ls.stream().max(Comparator.comparintInt(l -> {
if (l instanceof Ad) { return ((Ad) l).getProfit(); }
else if (l instanceof Ransom) { return ((Ransom) l).getProfit(); }
// ...
else { throw new IllegalArgumentException(...); }
}))

How to get rid of the inheritance?

I have an algorithm, and I have 2 different implementations of the algorithm. These implementations should be called from many places, depending on the mode selected by the user. I wouldn't like to write conditional statements at all places where implementations called. So, I create an abstract class and Implementations inherit it. I can set the desired mode in one place like this:
if(firstMode){
list = new ListForm1();
}
else{
list = new LiastForm2();
}
And after that in all other places I can enjoy all the benefits of polymorphism.
It works good but I want to get rid of the inheritance of the following reasons:
I heard that composition is much better than inheritance.
The first form of the algorith is much easier then the second form. In the first form I have only 3 methods and in second form I have 15 methods. The abstract class had to include all 15 (and 5 common methods). It turns out that the 12 methods not using by the first form.
Theoretically, there may be a new form of the algorithm, which will have even less in common with the other two, but it will bring 10 new methods and all of them will have to add an abstract class.
The Strategy Pattern, as I understand, does not make sense to use here.
Here is the example of Strategy Pattern:
//abstract strategy
interface Strategy {
int execute(int a, int b);
}
// concrete strategy1
class ConcreteStrategyAdd implements Strategy {
public int execute(int a, int b) {
return a + b;
}
}
// concrete strategy2
class ConcreteStrategySubtract implements Strategy {
public int execute(int a, int b) {
return a - b;
}
}
//concrete strategy3
class ConcreteStrategyMultiply implements Strategy {
public int execute(int a, int b) {
return a * b;
}
}
class Context {
private Strategy strategy;
public Context() {
}
// Set new concrete strategy
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
// use strategy
public int executeStrategy(int a, int b) {
return strategy.execute(a, b);
}
}
It has the same problems. Strategies should be linked with each other. If I link them with the interface instead of an abstract class it will be even worse. Interface will contain a lot of methods but many of them will not be needed for the first form of the algorithm. In addition, general methods have to duplicate in all concrete strategies. I can not provide a default implementation in the interface.
Moreever, I don't understand how to use composition here. As I understand, Strategy Pattern already used composition. Class Context includes the instance of Strategy as a field. But maybe it is delegation.
So, here is my question:
Can I get rid of all the above problems (too many methods of an abstract class, the strong connection, because of which it will be difficult to add a new form of an algorithm), but still use conditional statements in only one place, not in all cases when I need some form of algorithm.
UPD:
I want to show how I called some methods, which implemented in SECOND form of the algorithm, but not need for the FIRST form of algorithm:
if (list.getCurrentLeaders().contains(ballIdx))
The default implementation of method getCurrentLeaders() return null. So, if I called it with instance of the FIRST form of the algorithm then I will get an error. I understand that it is bad. But how can I solve it?
Starting from the beginning in the case you need to call a different algorithm based on a different mode chosen by the user you could create a kind of factory class to supply the algorithm throughout your code. I think that if it is only an algorithm and if you are on Java 8 you can use a Function or a Predicate or a Supplier in combination with a map to avoid the if statement, for example :
Map<String, Predicate<Whatever>> map = new HashMap<>();
map.put("mode_one", (w) -> true);
map.put("mode_two", (w) -> false);
Then to call the algorithm, simply :
map.get("mode_one").test()
In the case you need to supply a different form like in the example you posted, you could use a Supplier instead of a predicate.
Based on your simple requirement, I think that going functional would be the best bet ...
If you are not implementing all the methods (ie. if you have 15 methods in the abstract class to be implemented, and you only need to implement 10), then you are breaking the Liskov Substitution Principle :
https://en.wikipedia.org/wiki/Liskov_substitution_principle
Basically, that is a bad thing.
Try and convert the non-common methods into some other kind of object that gets passed into the constructor (on the abstract).
You can implement some kind of Chain Of Responsibility pattern.
interface IStrategy {
void Run();
bool CanHandle(IContext context);
}
class StrategyChecker {
IStrategy GetStrategy(IContext context) {
foreach(var strategy in strategies) {
if(strategy.CanHandle(context)
return strategy;
}
return defaultStrategy;
}
}
class Director {
void Run() {
strategyChecker.AddStrategy(strategy1);
strategyChecker.AddStrategy(strategy2);
var strategy = strategyChecker.GetStrategy(someContext);
strategy.Run();
}
}
Sorry for c# pseudo-code.
I heard that composition is much better than inheritance.
Not always - many times inheritance is the right construct. You have to think about it in has a and is a terms. A football team has a collection pf players. It also has a coach, a schedule, a name, etc. So Team : List<Player> is not the right construct.
A Car is a Vehicle, so inheritance is the right construct.
So think about your design this way:
Do my classes share a common base? Is there a base class that makes sense to say ListForm1 is a ListBase and ListForm2 is a ListBase. What methods and properties are common to those types that should be in the case type? What methods and properties should be virtual so that I can override them?
The first form of the algorithm is much easier then the second form. In the first form I have only 3 methods and in second form I have 15 methods. The abstract class had to include all 15 (and 5 common methods). It turns out that the 12 methods not using by the first form.
So maybe your base type only 3 methods, and you add methods in the sub-types as necessary. Remember that you can have multiple base types in the chain, but it's a chain, not a tree, meaning you can have a single parent that has another parent, but you can't have two parents.
Or maybe you have orthogonal interfaces since you can implement multiple interfaces.
Theoretically, there may be a new form of the algorithm, which will have even less in common with the other two, but it will bring 10 new methods and all of them will have to add an abstract class.
Why? Why can't the new algorithm just define its own methods that it needs, so long as clients pick the appropriate level in the inheritance chain (or appropriate interface(s)) so that it knows what methods should be implemented.
if (list.getCurrentLeaders().contains(ballIdx))
The default implementation of method getCurrentLeaders() return null. So, if I called it with instance of the FIRST form of the algorithm then I will get an error. I understand that it is bad. But how can I solve it?
So do you need to check that this particular list implements an interface (or inherits a base class) that does implement that method?
Why not just use your IStrategy as a type?
interface IStrategy {
int execute(int a, int b);
}
class Strategy1 implements IStrategy {}
class Strategy2 implements IStrategy {}
static class StrategyFactory {
IStrategy Create(bool first) {
return first ? new Strategy1() : new Strategy2();
}
}
And then in your user code:
void doStuff()
{
IStrategy myStrategy = StrategyFactory.Create(true);
myStrategy.execute(1, 2);
}

How can I simulate Enums that can be expanded at Runtime in Java?

I am writing a program to simulate cities from a game called Civilization 4. In order to do this I have several Enums to represent types of terrain, resources, improvements etc for each plot owned by said city.
The problem is I want to program to be compatible with Fan made mods which may add things to the Game that need to be accepted into my independant utility. So I thought of creating a Enum style class to hold the new types defined by the loaded mods (as Enums cannot be changed at runtime) which is created during runtime when the user enters in a mod to be loaded (which is a txt file that is parsed to read the new additions)
So is there a way to simulate Enums that are created and added to at runtime? I take it static member variables cannot be used as they are done before runtime...
You can make a enum implement an interface.
This way you can have your defined values in the enum, but new values can be any class which implements the interface.
An alternative is that you generate or load the enum at runtime using a byte code generator or the Compiler API. I wrote a library to make it easier to take a String and compile&load it.
http://vanillajava.blogspot.co.uk/2010_11_01_archive.html
Well, enums in Java are simply classes where the language guarantees that the set of known objects is known and limited at compile-time. If you want to add new enum literals at runtime, you end up with regular classes.
The beauty of enums is that you can write human readable names in code that are compiled as numbers behind the scenes, because computers like numbers better. Take for example this enum:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
Behind the scenes WINTER might be 0 (zero), SPRING is 1 etc.
To replicate this behaviour in runtime code you could create a list of strings, like this:
List<String> seasons;
seasons = new ArrayList<String>();
seasons.add("Winter");
seasons.add("Spring");
...
That way you can reference the items as numbers, such as seasons[1] would equal "Spring".
This answer is just one of many ways to approach this question.
By default, enum types have only a set number of values. The values in an enum type are actually declared as static final, and there's no way to add more on runtime.
That being said, there are other patterns you can use to implement what you want. Let's take a look at using an interface and a registration system. We'll start with the Terrain interface:
public interface Terrain {
int getId();
String getName();
int getSightBonus();
}
Now an enum, DefaultTerrain:
public enum DefaultTerrain implements Terrain {
PLAINS(0, "Plains", 1),
HILLS(1, "Hills", -1),
MOUNTAINS(2, "Mountains", -2);
private int id;
private String name;
private int sightBonus;
private DefaultTerrain(int id, String name, int sightBonus) {
this.id = id;
this.name = name;
this.sightBonus = sightBonus;
}
public int getId() {return id;}
public String getName() {return name;}
public int getSightBonus() {return sightBonus;}
}
And a registration class, which can be either a static utility class or a singleton.
public class TerrainManager {
private static Map<Integer, Terrain> terrainsById = new HashMap<>();
static {
for (DefaultTerrain terrain : DefaultTerrain.values())
register(terrain);
}
public static void register(Terrain terrain) {
Integer id = terrain.getId();
if (terrainsById.contains(terrain.getId()))
throw new IllegalArgumentException("Terrain with id already exists: " + id);
terrainsById.put(id, terrain);
}
public static Terrain getTerrainById(int id) {
return terrainsById.get(id);
}
public static Set<Terrain> getAllTerrains() {
return new HashSet<Terrain>(terrainsById.values());
}
}
This last class is where the magic happens. Presumably the modders will have some kind of identifier in the game's world definition to say "use this tile," right? In this case, I've called it an integer, id, but really it could be any type, just modify the Map accordingly. In the map-loading code, just use the ID in the world definition to look up the Terrain. When a modder adds a new Terrain, they just need to implement Terrain and register it with TerrainManager.
The static initializer makes sure that your DefaultTerrain objects are added before anything else is added. If you use a singleton, this could be put into the class constructor instead.
Use this pattern for your different enum types that you want users to add to. You could also use it for pretty much any other type as well besides enum.
You will need CGLIB, http://cglib.sourceforge.net/

Handling a binary operation that makes sense only for part of a hierarchy

I have a hierarchy, which I'll simplify greatly, of implementations of interface Value. Assume that I have two implementations, NumberValue, and StringValue.
There is an average operation which only makes sense for NumberValue, with the signature
NumberValue average(NumberValue numberValue){
...
}
At some point after creating such variables and using them in various collections, I need to average a collection which I know is only of type NumberValue, there are three possible ways of doing this I think:
Very complicated generic signatures which preserve the type info in compile time (what I'm doing now, and results in hard to maintain code)
Moving the operation to the Value level, and: throwing an unsupportedOperationException for StringValue, and casting for NumberValue.
Casting at the point where I know for sure that I have a NumberValue, using slightly less complicated generics to insure this.
Does anybody have any better ideas, or a recommendation on oop best practices?
As #tafa said, it seems to me an interface would be a good choice. Based on your signature for average, I came up with the below.
AveragableValue
public interface AveragableValue<T> extends Value
{
public T average(T value);
}
NumberValue
public class NumberValue implements AveragableValue<NumberValue>
{
private int _n;
public NumberValue(int n)
{
this._n = n;
}
#Override
public void doSomething()
{
// from Value interface
}
#Override
public NumberValue average(NumberValue value)
{
return new NumberValue((this._n + value._n) / 2);
}
}
Then you can have your collection be of type AveragableValue. Already in your code you must have some kind of if/else clause somewhere to differentiate NumberValue and StringValue to figure out whether to call average or not. So I don't see how this would be more complicated. The hierarchy make sense - AveragableValues are a subtype of Value, and a NumberValue is a type of AveragableValue.
However, that signature for average doesn't look right. It only takes 2 values (this and the argument) and averages them. You then lose the total count of things that have been averaged before. So assuming integers as the values (as I did), something like this:
(new NumberValue(4)).average(new NumberValue(8)).average(new NumberValue(12));
would give you the value 9 instead of 8. Is this what you want? It makes it bad for many calculations done iteratively, as you may be doing with collections.
If you show us some of your code - how these classes are used, the collections holding them, how you are doing averaging right now - I can maybe give a better answer.
I would have create another interface IAveragable which contains the average operation which derives from Value . Then StringValue would implement just Value interface and NumberValue would implement IAveragable.
Then when it is required to use the average operation I would check if the object implements IAveragable.
I'm unable to comment, therefore I'll just post a new answer.
Create an interface for value:
public interface Value<T> {
public T getValue();
}
And one for averagable:
public interface Averagable<T> {
public T average(T value);
}
Then a number value would be something like:
public class NumberValue implements Averagable<Number>, Value<Number>{
public Number average(Number value) {
// do your stuff
}
public Number getValue() {
// do your stuff
}
}
There is no need to let Averagable extend from Value.

Categories