How do you deal with having only single inheritance in java? Here is my specific problem:
I have three (simplified) classes:
public abstract class AbstractWord{
String kind; // eg noun, verb, etc
public String getKind(){ return kind; }
}
public class Word extends AbstractWord{
public final String word;
ctor...
public void setKind(){
// based on the variable word calculate kind..
}
}
public class WordDescriptor extends AbstractWord{
ctor..
public void setKind(String kind){this.kind = kind;}
}
This is what I consider my most basic implementation but I want to make other implementations.
Lets say that I want to add a new variable say wordLength but I want to add it using inheritance. Meaning I do NOT want modify that original AbstractWord class. Ie something along the lines of this:
public class Length{
private int length;
public int getLength(){return length};
}
public class BetterWord extends AbstractWord AND Length{
public void setLength(){
// based on the variable word calculate Length..
}
}
public class BetterWordDescriptor extends AbstractWord AND length{
public void setLength(int length){this.length = length;}
}
I know that java does not let me do this but it has made my code very ugly. Right now whenever I add a field I am just adding it to AbstractWord but then I either need to rename that AbstractWord (and Word and WordDescriptor). (I can't just add the field to the other one because of backwards compatibility, it break equals methods and stuff like that).
This seems like a pretty common design issue but I have racked my head and I cannot come up with any beautiful solutions.
Is there a design pattern that addresses this? I have some potential solutions but I wanted to see if there was something that I was missing.
thanks,
Jake
Update: Length refers to the number of syllables in the word (sorry about the lack of clarity)
Favor composition over inheritance.
Solution takes into consideration that there could be another type of word that may need WordLengthSupport.
Similarly other interfaces could be created and implemented and various word types can have mix and match of those interfaces.
.
public class WordLength {
private int length = 0;
public int getLength(){return length};
public void setLength(int length){this.length = length};
}
.
public interface WordLengthSupport {
public WordLength getWordLength();
}
.
public class BetterWord extends AbstractWord
implements WordLengthSupport {
WordLength wordLength;
public WordLength getWordLength() {
if(wordLength==null) {
// each time word changes
// make sure to set wordLength to null
calculateWordLength();
}
return wordLength;
}
private void calculateWordLength() {
// This method should be
// called in constructor
// or each time word changes
int length = // based on the variable word calculate Length..
this.wordLength = new WordLength();
this.wordLength.setLength(length);
}
}
.
public class BetterWordDescriptor extends AbstractWord
implements WordLengthSupport {
WordLength wordLength;
public WordLength getWordLength(return wordLength);
public void setWordLength(WordLength wordLength) {
// Use this to populate WordLength of respective word
this.wordLength = wordLength;
}
}
.
The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
This solution does not use strategy pattern but can be refactored for same.
Just use composition instead of inheritance:
a BetterWord is-an AbstractWord that has-a Length:
public class BetterWord extends AbstractWord {
private Length length;
public void setLength(int value){
length.setLength(value);
}
}
EDIT
If the API needs an object of type Length, just add a getter:
public class BetterWord extends AbstractWord {
private Length length;
public void setLength(int value){
length.setLength(value);
}
public Length getLength() {
return length
}
}
Or rename the implementation Length to LengthImpl and define an interface Length, because a class can implement multiple interfaces.
With your specific example you could use the decorator pattern in conjunction with interfaces to supplement your Word class with additional functionality; e.g.
// *Optional* interface, useful if we wish to reference Words along with
// other classes that support the concept of "length".
public interface Length {
int getLength();
}
// Decorator class that wraps another Word and provides additional
// functionality. Could add any additional fields here too.
public class WordExt extends AbstractWord implements Length {
private final Word word;
public class(Word word) {
this.word = word;
}
public int getLength() {
return word.getKind().length();
}
}
In addition it's worth noting that the lack of multiple inheritence in Java isn't really the issue here; it's more a case of reworking your design. In general it's considered bad practice to over-use inheritence as deep inheritence hierarchies are difficult to interpret / maintain.
Looking at it, my first feeling is that your model is a bit complicated.
A word has a String to describe the word itself being stored in the Word object along with a class to say it's a noun, verb, adjective, etc. Another property of a Word is the length of the string stored in the Word object.
Think of things in terms of "is-a" and "has-a" relationships and you can remove a lot of complexity.
For instance why do you need a WordDescriptor that extends AbstractWord? Is a word going to change from a verb to an adjective? I would have thought that the word type was set when the object was created and would not change during the lifetime of the Word object. Once you had a Word object for the word "Australia" the Kind of word would not change for the lifetime of the object.
Hmmm. Maybe you might have a Word object representing the word "bark" after instantiating the object with a type of "verb" to describe the sound a dog makes. Then you realise that you actually needed to have the Word object to represent a noun that describes the covering of a tree. Possible, but both the dog's bark and the tree's bark can exist.
So I think the model you've chosen is a bit too complicated and that your question can be resolved by going back and simplifying your original object model.
Start by asking yourself a question for each of the inheritance aspects of your basic model.
When I say Class B extends Class A, can I say that Class B "is-a" Class A and that I am specialising its behaviour?
For example, a base class Animal can be extended to provide the specialised class of Kangaroo. Then you can say that "the kangaroo "is-a" Animal. You are specialising the behaviour.
Then look at the attributes, a Kangaroo has a Location attribute to describe where it is found. Then you can say a Kangaroo "has-a" location. A Kangaroo "is-a" location doesn't make sense.
Similarly, a Word "has-a" length. And the statement a Word "is-a" length just doesn't make sense.
BTW All Australian references in this post are deliberate to celebrate Australia Day which is today 26th January!
HTH
(I can't just add the field to the other one because of backwards compatibility, it break equals methods and stuff like that).
It won't break source compatibility. Not unless you're doing something really crazy in your equals methods.
And renaming your classes is generally not the way to handle binary compatibility.
The problem is not "how to deal with single inheritance". What you're missing is not really a design pattern but learning to design the API separately from the implementation.
I would implement it like so:
public interface WordDescriptor {
void getKind();
Word getWord();
}
public interface Word {
String getWord();
}
public class SimpleWord implements Word {
private String word;
public SimpleWord(String word) { this.word = word; }
public String getWord() { return word; }
}
public class SimpleWordDescriptor implements WordDescriptor {
private Word word;
private String kind;
public SimpleWordDescriptor(Word word, String kind) {
this.word = word;
this.kind = kind; // even better if WordDescriptor can figure it out internally
}
public Word getWord() { return word; }
public String getKind() { return kind; }
}
With this basic setup, when you want to introduce a length property, all you have to do is this:
public interface LengthDescriptor {
int getLength();
}
public class BetterWordDescriptor extends SimpleWordDescriptor
implements LengthDescriptor {
public BetterWordDescriptor(Word word, String kind) {
super(word, kind);
}
public int getLength() { getWord().length(); }
}
The other answers that uses composition of properties as well as the Decorator pattern are also entirely valid solutions to your problem. You just need to identify what your objects are and how "composable" they are, and how they are to be used - hence designing the API first.
/**
* First example
*/
class FieldsOfClassA {
public int field1;
public char field2;
}
interface IClassA {
public FieldsOfClassA getFieldsA();
}
class CClassA implements IClassA {
private FieldsOfClassA fields;
#Override
public FieldsOfClassA getFieldsA() {
return fields;
}
}
/**
* seems ok for now
* but let's inherit this sht
*/
class FieldsOfClassB {
public int field3;
public char field4;
}
interface IClassB extends IClassA {
public FieldsOfClassA getFieldsA();
public FieldsOfClassB getFieldsB();
}
class CClassB implements IClassB {
private FieldsOfClassA fieldsA;
private FieldsOfClassB fieldsB;
#Override
public FieldsOfClassA getFieldsA() {
return fieldsA;
}
#Override
public FieldsOfClassB getFieldsB() {
return fieldsB;
}
}
/**
wow this monster got bigger
imagine that you will need 4 lvl of inheritance
it would take so much time to write this hell
I'm even not talking that user of those iface will think
what fields i will need fieldsA fieldsB fieldsC or another one
So composition does not work here
and your pathetic tries are useless
When u think about Oject Oriented programming
u need BIG models with 6-7 lvls of multiple inheritance
because that is good test and because corresponds to models of real life or math models tested by civilization for 4 thousands years.
If your models require 2 lvl of inheritance stop pretending u using OO
U can easily implement it with any language even procedural one like C or Basic language
*/
Related
Sealed classes and sealed interfaces were a preview feature in Java 15, with a second preview in Java 16, and now proposed delivery in Java 17.
They have provided classic examples like Shape -> Circle, Rectangle, etc.
I understand sealed classes: the switch statement example provided makes sense to me. But, sealed interfaces are a mystery to me. Any class implementing an interface is forced to provide definitions for them. Interfaces don't compromise the integrity of the implementation because the interface is stateless on its own. Doesn't matter whether I wanted to limit implementation to a few selected classes.
Could you tell me the proper use case of sealed interfaces in Java 15+?
Basically to give a sealed hierarchy when there is no concrete state to share across the different members. That's the major difference between implementing an interface and extending a class - interfaces don't have fields or constructors of their own.
But in a way, that isn't the important question. The real issue is why you would want a sealed hierarchy to begin with. Once that is established it should be clearer where sealed interfaces fit in.
(apologies in advance for the contrived-ness of examples and the long winded-ness)
1. To use subclassing without "designing for subclassing".
Lets say you have a class like this, and it is in a library you already published.
public final class Airport {
private List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
public void bookPeople(String... names) {
for (String name : names) {
this.bookPerson(name);
}
}
public int peopleBooked() {
return this.peopleBooked.size();
}
}
Now, you want to add a new version to your library that will print out the names of people booked as they are booked. There are several possible paths to do this.
If you were designing from scratch, you could reasonably replace the Airport class with an Airport interface and design the PrintingAirport to compose with a BasicAirport like so.
public interface Airport {
void bookPerson(String name);
void bookPeople(String... names);
int peopleBooked();
}
public final class BasicAirport implements Airport {
private final List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
#Override
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
#Override
public void bookPeople(String... names) {
for (String name : names) {
this.bookPerson(name);
}
}
#Override
public int peopleBooked() {
return this.peopleBooked.size();
}
}
public final class PrintingAirport implements Airport {
private final Airport delegateTo;
public PrintingAirport(Airport delegateTo) {
this.delegateTo = delegateTo;
}
#Override
public void bookPerson(String name) {
System.out.println(name);
this.delegateTo.bookPerson(name);
}
#Override
public void bookPeople(String... names) {
for (String name : names) {
System.out.println(name);
}
this.delegateTo.bookPeople(names);
}
#Override
public int peopleBooked() {
return this.peopleBooked.size();
}
}
This isn't doable in our hypothetical though because the Airport class already exists. There are going to be calls to new Airport() and methods that expect something of type Airport specifically that can't be kept in a backwards compatible way unless we use inheritance.
So to do that pre-java 15 you would remove the final from your class and write the subclass.
public class Airport {
private List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
public void bookPeople(String... names) {
for (String name : names) {
this.bookPerson(name);
}
}
public int peopleBooked() {
return this.peopleBooked.size();
}
}
public final class PrintingAirport extends Airport {
#Override
public void bookPerson(String name) {
System.out.println(name);
super.bookPerson(name);
}
}
At which point we run into one of the most basic issues with inheritance - there are tons of ways to "break encapsulation". Because the bookPeople method in Airport happens to call this.bookPerson internally, our PrintingAirport class works as designed, because its new bookPerson method will end up being called once for every person.
But if the Airport class were changed to this,
public class Airport {
private List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
public void bookPeople(String... names) {
for (String name : names) {
this.peopleBooked.add(name);
}
}
public int peopleBooked() {
return this.peopleBooked.size();
}
}
then the PrintingAirport subclass won't behave correctly unless it also overrided bookPeople. Make the reverse change and it won't behave correctly unless it didn't override bookPeople.
This isn't the end of the world or anything, its just something that needs to be considered and documented - "how do you extend this class and what are you allowed to override", but when you have a public class open to extension anyone can extend it.
If you skip documenting how to subclass or don't document enough its easy to end up in a situation where code you don't control that uses your library or module can depend on a small detail of a superclass that you are now stuck with.
Sealed classes let you side step this by opening your superclass up to extension only for the classes you want to.
public sealed class Airport permits PrintingAirport {
// ...
}
And now you don't need to document anything to outside consumers, just yourself.
So how do interfaces fit in to this? Well, lets say you did think ahead and you have the system where you are adding features via composition.
public interface Airport {
// ...
}
public final class BasicAirport implements Airport {
// ...
}
public final class PrintingAirport implements Airport {
// ...
}
You might not be sure that you don't want to use inheritance later to save some duplication between the classes, but because your Airport interface is public you would need to make some intermediate abstract class or something similar.
You can be defensive and say "you know what, until I have a better idea of where I want this API to go I am going to be the only one able to make implementations of the interface".
public sealed interface Airport permits BasicAirport, PrintingAirport {
// ...
}
public final class BasicAirport implements Airport {
// ...
}
public final class PrintingAirport implements Airport {
// ...
}
2. To represent data "cases" that have different shapes.
Lets say you send a request to a web service and it is going to return one of two things in JSON.
{
"color": "red",
"scaryness": 10,
"boldness": 5
}
{
"color": "blue",
"favorite_god": "Poseidon"
}
Somewhat contrived, sure, but you can easily imagine a "type" field or similar that distinguishes what other fields will be present.
Because this is Java, we are going to want to map the raw untyped JSON representation into classes. Lets play out this situation.
One way is to have one class that contains all the possible fields and just have some be null depending.
public enum SillyColor {
RED, BLUE
}
public final class SillyResponse {
private final SillyColor color;
private final Integer scaryness;
private final Integer boldness;
private final String favoriteGod;
private SillyResponse(
SillyColor color,
Integer scaryness,
Integer boldness,
String favoriteGod
) {
this.color = color;
this.scaryness = scaryness;
this.boldness = boldness;
this.favoriteGod = favoriteGod;
}
public static SillyResponse red(int scaryness, int boldness) {
return new SillyResponse(SillyColor.RED, scaryness, boldness, null);
}
public static SillyResponse blue(String favoriteGod) {
return new SillyResponse(SillyColor.BLUE, null, null, favoriteGod);
}
// accessors, toString, equals, hashCode
}
While this technically works in that it does contain all the data, there isn't all that much gained in terms of type-level safety. Any code that gets a SillyResponse needs to know to check the color itself before accessing any other properties of the object and it needs to know which ones are safe to get.
We can at least make the color an enum instead of a string so that code shouldn't need to handle any other colors, but its still far less than ideal. It gets even worse the more complicated or more numerous the different cases become.
What we ideally want to do is have some common supertype to all the cases that you can switch on.
Because its no longer going to be needed to switch on, the color property won't be strictly necessary but depending on personal taste you can keep that as something accessible on the interface.
public interface SillyResponse {
SillyColor color();
}
Now the two subclasses will have different sets of methods, and code that gets either one can use instanceof to figure out which they have.
public final class Red implements SillyResponse {
private final int scaryness;
private final int boldness;
#Override
public SillyColor color() {
return SillyColor.RED;
}
// constructor, accessors, toString, equals, hashCode
}
public final class Blue implements SillyResponse {
private final String favoriteGod;
#Override
public SillyColor color() {
return SillyColor.BLUE;
}
// constructor, accessors, toString, equals, hashCode
}
The issue is that, because SillyResponse is a public interface, anyone can implement it and Red and Blue aren't necessarily the only subclasses that can exist.
if (resp instanceof Red) {
// ... access things only on red ...
}
else if (resp instanceof Blue) {
// ... access things only on blue ...
}
else {
throw new RuntimeException("oh no");
}
Which means this "oh no" case can always happen.
An aside: Before java 15 to remedy this people used the "type safe visitor" pattern. I recommend not learning that for your sanity, but if you are curious you can look at code ANTLR generates - its all a large hierarchy of differently "shaped" data structures.
Sealed classes let you say "hey, these are the only cases that matter."
public sealed interface SillyResponse permits Red, Blue {
SillyColor color();
}
And even if the cases share zero methods, the interface can function just as well as a "marker type", and still give you a type to write when you expect one of the cases.
public sealed interface SillyResponse permits Red, Blue {
}
At which point you might start to see the resemblance to enums.
public enum Color { Red, Blue }
enums say "these two instances are the only two possibilities." They can have some methods and fields to them.
public enum Color {
Red("red"),
Blue("blue");
private final String name;
private Color(String name) {
this.name = name;
}
public String name() {
return this.name;
}
}
But all instances need to have the same methods and the same fields and those values need to be constants. In a sealed hierarchy you get the same "these are the only two cases" guarantee, but the different cases can have non-constant data and different data from each other - if that makes sense.
The whole pattern of "sealed interface + 2 or more record classes" is fairly close to what is intended by constructs like rust's enums.
This also applies equally to general objects that have different "shapes" of behaviors, but they don't get their own bullet point.
3. To force an invariant
There are some invariants, like immutability, that are impossible to guarantee if you allow subclasses.
// All apples should be immutable!
public interface Apple {
String color();
}
public class GrannySmith implements Apple {
public String color; // granny, no!
public String color() {
return this.color;
}
}
And those invariants might be relied upon later on in the code, like when giving an object to another thread or similar. Making the hierarchy sealed means you can document and guarantee stronger invariants than if you allowed arbitrary subclassing.
To cap off
Sealed interfaces more or less serve the same purpose as sealed classes, you just only use concrete inheritance when you want to share implementation between classes that goes beyond what something like default methods can give.
Although interfaces have no state themselves, they have access to state, eg via getters, and may have code that does something with that state via default methods.
Therefore the reasoning supporting sealed for classes may also be applied to interfaces.
Suppose you write an authentication library, containing an interface for password encoding, ie char[] encryptPassword(char[] pw). Your library provides a couple of implementations the user can choose from.
You don't want him to be able to pass in his own implementation that might be insecure.
Could you tell me the proper use case of sealed interfaces in Java
15+?
I wrote some experimental code and a supporting blog to illustrate how sealed interfaces could be used to implement an ImmutableCollection interface hierarchy for Java that provides contractual, structural and verifiable immutability. I think this could be a practical use case for sealed interfaces.
The example includes four sealed interfaces: ImmutableCollection, ImmutableSet, ImmutableList and ImmutableBag. ImmutableCollection is extended by ImmutableList/Set/Bag. Each of the leaf interfaces permits two final concrete implementations. This blog describes the design goal of restricting the interfaces so developers cannot implement "Immutable" interfaces and provide implementations that are mutable.
Note: I am a committer for Eclipse Collections.
Interfaces are not always entirely defined by their API alone. Take, for example ProtocolFamily. This interface would be easy to implement, considering its methods, but the result would not be useful regarding the intended semantics, as all methods accepting ProtocolFamily as input would just throw UnsupportedOperationException, in the best case.
This is a typical example for an interface that would be sealed if that feature existed in earlier versions; the interface is intended to abstract the implementations exported by a library, but not to have implementations outside that library.
The newer type ConstantDesc mentions that intention even explicitly:
Non-platform classes should not implement ConstantDesc directly. Instead, they should extend DynamicConstantDesc…
API Note:
In the future, if the Java language permits, ConstantDesc may become a sealed interface, which would prohibit subclassing except by explicitly permitted types.
Regarding possible use cases, there is no difference between a sealed abstract class and a sealed interface, but the sealed interface still allows implementors extending different classes (within the limits set by the author). Or being implemented by enum types.
In short, sometimes, interfaces are used to have the least coupling between a library and its clients, without the intention of having client-side implementations of it.
Since Java introduced records in version 14, one use case for sealed interfaces will certainly be to create sealed records. This is not possible with sealed classes, because records cannot extend a class (much like enums).
Before java 15 developers used to think in a way that code reusability is the goal. But it's not true to all extents, in some cases we want wide accessibility but not extensibility for better security and also codebase management.
This feature is about enabling more fine-grained inheritance control in Java. Sealing allows classes and interfaces to define their permitted subtypes.
The sealed interface allows us to enable it to reason clearly all the classes that can implement it.
I studied about SOLID Principle and created a question for me about it.
you suppose that we need a Tea Object in Mug class, now is this better than create a instance from Tea in Mug class or pass from outside through Constructor or setter method.
which on is true?
example:
class Mug {
private Tea tea;
public Mug(){
this.tea = new Tea();
}
public boolean isFull(){
return this.tea.value != 10;
}
}
or
class Mug {
private Tea tea;
public Mug(Tea tea){
this.tea = tea;
}
// public void setTea(Tea tea){
// this.tea = tea;
// }
public boolean isFull(){
return this.team.value != 10;
}
}
use:
public class Test {
static void main(String[] args){
Mug mug = new Mug();
//or
Mug mug = new Mug(new Tea());
}
}
which one is better?
NOTE: Suppose that Mug support only Tea object in our program.
Both of your cases violate SOLID.
Your each concrete implementation (concrete class) should only be dependent upon Abstractions.
in your case Tea is not an abstraction. Mug has tight coupling with Tea. Below is a possible way to code it.
public interface ITea{
//tea related methods which you think should be exposed to outside world. Also all implementation of ITea must support these method (L in SOLID)
}
public class Tea implements ITea{
// Implement the contract methods from ITea
}
public class Mug {
private ITea tea;
// Have constructor or setter to inject concrete implementation. Setter will provide you capability to modify behavioral at run time.
}
EDIT:
1. If we are sure there is only one possible implementation Of tea. Then also interface is better as concrete implementations are hard to mock and hence makes unit testing is difficult.
Avoid using enums for setting type. Enums inject switch cases and in future if a case is added all such switch cases needs to be modified leading to violation of O in SOLID.
If a case is added you have to modify existing code and in case you forget to add a case somewhere it leads to unexpected errors. (It violates OCP. Instead of enums put logic in specific implementation, have common interface and specific implementation). Also if we implement the case specific logic in individual instances of enum then the enum file will become gigantic. Instead if we have specific logic in individual concrete classes implementing common interface makes the user code easy as it can be injected with concrete classes in a polymorphic way.
p.s. this answer is about following the principles and it's not always possible to do so. It's fine to violate the principle but we must know that we are violating it, and have a very good reason to do so.
I would use the second one where possible, injecting a classes dependencies, take this example where the Tea constructor requires more information:
class Mug {
private Tea tea;
public Mug(int temperature) {
this.tea = new Tea(temperature);
}
public boolean isFull() {
return tea.value != 10;
}
}
See how ugly that is that Mug's constructor now needs information only used by Tea's constructor.
But as it stands I would say that neither of your examples violates any SOLID principle.
There is nothing that says you can't create a new object inside another and nothing that says you must create abstractions.
Here would be a real violation in this area:
class Mug { // VIOLATION
private Tea tea;
private Coffee coffee;
public Mug(boolean tea) {
if (tea) {
this.tea = new Tea();
} else {
this.coffee = new Coffee();
}
}
public boolean isFull() {
return tea.value != 10 || coffee.value != 10;
}
}
The class depends upon multiple similar classes. Compare to:
class Mug {
private Liquid liquid;
public Mug(Liquid liquid) {
this.liquid = liquid;
}
public boolean isFull() {
return liquid.getVolume() != 10;
}
}
interface Liquid {
int getVolume();
}
class Tea implements Liquid {
private int volume;
#Override
public int getVolume() {
return volume;
}
}
class Coffee implements Liquid {
private int volume;
#Override
public int getVolume() {
return volume;
}
}
But as you only have one thing that can go in a Mug there is no violation and no need for an abstraction. In general, never write any code that doesn't solve a problem.
And never create an abstraction with a name like ITea. In such a case either the concrete class name is not specific enough, or the abstraction name is not general enough.
let's say that I have several Creature subclasses, and that they have each have some sort of getGroup() method that returns a List<Creature>.
What I mean by "some sort of" .getGroup() method is that the name of this function varies between subclasses. For instance, Wolfs travel in packs, so they have a getPack() member. Fish travel in schools, so they have a .getSchool() member, Humans have a getFamily() member, and so on.
.getGroup() doesn not exist in Creature, and it cannot be added to the interface. None of these clases can be edited.
I'm writing a method to print the number of Creatures in their group. How would I do this?
Essentially, I'm looking to condense these two functions into the same thing:
public void PrintSchoolSize(Fish dory) {
System.out.print(dory.getSchool().size());
}
public void PrintHiveSize(Bee bee) {
System.out.print(bee.getColony().size());
}
...into the following function:
public void printGroupSize( Class<? extends Creature> cree,
FunctionThatReturnsList getGroup() ) {
System.out.print(cree.getGroup().size();
}
I'd imagine I need to pass in a second argument (function pointer?) to void printGroupSize. Any help is very appreciated, thanks!
EDIT Thank you all for the help. This is just a simplification of the real problem I'm trying to solve. Long, overly complex problems are tougher to answer, so I posed this simpler scenario.
The only answer lies in using a generic function (if that exists). The classes I'm actually working with don't have a common interface, but they all have a function that returns a List.
What you describe in your question is not much related to Java's sense of "generic methods". You could implement it with reflection (see Class.getMethod()), but I promise you that you really don't want to go there.
It would be better for Creature to declare a possibly-abstract method getGroup() that each subclass would override. You may do that in addition to providing methods with subclass-specific names, if you wish. Code that wants to obtain the group (or its size) without knowing the specific type of creature would invoke that creature's getGroup() method. That's an application of polymorphism, which seems to be what you're actually after.
If getGroup cannot be added to the Creature interface why not add another interface to your creatures?
public interface HasGroup {
Group getGroup();
}
Would mean you can create the method:
public void printGroupSize(HasGroup cree) {
System.out.print(cree.getGroup().size();
}
The simplest way is to had a getGroup() method to the Creature interface and implement it in each subclass, but it seems you cannot do that.
If you can modify the subclasses, I would actually create a new interface CreatureGroupable with a getGroupSize() and/or getGroup(). Each subclass of Creature shall implement this interface, e.g.
public interface CreatureGroupable {
CreatureGroup getGroup();
}
public enum CreatureGroup {
WOLF_PACK("pack", 30),
GEES_FLOCK("flock", 20),
FISH_SCHOOL("school", 1000),
HUMAN_FAMILY("family", 4),
...
private final String name;
private final int size;
private CreatureGroup(String name, int size) {
this.name = name;
this.size = size;
}
public String getName() { return name; }
public int getSize() { return size; }
}
public class Wolf implements Creature, CreatureGroupable {
// methods from Creature, constructor, ...
public CreatureGroup getGroup() {
return CreatureGroup.WOLF_PACK;
}
This way, if you have a List<Creature> you can access the group of each one and do whatever you have to do, e.g.
public void printGroups(List<Creature> creatures) {
for (Creature c : creatures) {
CreatureGroup group = c.getGroup();
System.out.println("A " + group.getName() +
" has roughly " group.getSize() +
" individuals.");
}
}
If you want more flexibility, you may not use an enum and just a standard interface and class hierarchy for the groups.
Thanks to everyone for the help. Since I'm not allowed to edit any of the aforementioned classes/interfaces (I can only write external functions), I wrote the following function
public List<? extends Creature> getGroup(Object obj) {
if(obj.getClass() == Bee.class)
return ((Bee)obj).getColony();
if(obj.getClass() == Fish.class)
return ((Fish) obj).getSchool();
/* repeat for the other classes */
return null;
}
...and used it here, as so:
public void printGroupSize( Class<? extends Creature> cree ) {
System.out.print(getGroup(cree).size());
}
I have verified that this solution does indeed work, since all of the get*****() functions return a List<Creature>. This solution also shrinks my codebase significantly, and is easier to maintain than the current structure.
I know that it isn't possible to extend enum in Java, but I am trying to find an elegant solution for the below
I am trying to model enums (or classes) which will contain http end points of various web services across regions, say I have service A and B, each will have 4 region specific end points in US, EU, JP or CN. (This is basically for some seperate debug code that I am writing, in production the end points will be picked from configuration)
I was hoping to do something like this (not compliant java code).
public enum IEndPoint {
NA_END_POINT,
EU_END_POINT,
JP_END_POINT,
CN_END_POINT,
}
public enum ServiceAEndPoint extends IEndPoint {
NA_END_POINT("http://A.com/");
EU_END_POINT("http://A-eu.com/");
JP_END_POINT("http://A-jp.com/");
CN_END_POINT("http://A-cn.com/");
}
I could do this using interfaces where I have a method for each region, but in my opinion the enum way is more expressive, is there any better way I could model this ? What I am looking for is if there is any better way to model the inheritence relation and also having the expressive power of enumerations.
ServiceAEndPoint.NA_END_POINT
vs
serviceAEndPoint.getNAEndPoint()
I'm assuming that you will also want a ServiceBEndPoint enum (and similar). In which case I don't think your model really makes that much sense.
IEndPoint is really an enumeration of the kind of environments/regions where a service might be running. It is not an enumeration of the services themselves. Each individual service (A, B or whatever) will have different addresses for each of the regions.
Therefore I would stick with just the IEndPoint enum, and then in some service-specific code have a lookup map that will give you the address for a given end-point. Something like this:
public enum IEndPoint {
NA_END_POINT,
EU_END_POINT,
JP_END_POINT,
CN_END_POINT,
}
public class ServiceABroker {
private static final Map<IEndPoint, String> addressesByEndPoint;
static {
addressesByEndPoint = new EnumMap<>();
addressesByEndPoint.put(NA_END_POINT, "http://A.com/");
addressesByEndPoint.put(EU_END_POINT, "http://A-eu.com/");
addressesByEndPoint.put(JP_END_POINT, "http://A-jp.com/");
addressesByEndPoint.put(CN_END_POINT, "http://A-cn.com/");
}
public String getAddressForEndPoint(IEndPoint ep) {
return addressesByEndPoint.get(ep);
}
}
If these are static final constants, then just put them in an interface. Name the interface something like IServiceAEndPointKeys, where the keys part is a convention.
Here's where I consider enums to be more appropriate and useful:
Example 1: File type. An enum containing jpg, pdf etc.
Example 2: Column definitions. If I have a table with 3 columns, I would write an enum declaring ID, Name, Description (for example), each one having parameters like column header name, column width and column ID.
Im not sure I understand you question, but you can add methods to an enum for example you could do something like the following:
public enum ServiceAEndPoint{
NA_END_POINT("http://A.com/");
EU_END_POINT("http://A-eu.com/");
JP_END_POINT("http://A-jp.com/");
CN_END_POINT("http://A-cn.com/");
private final String url;
private EndPoint(String url){
this.url=url;
}
public String getURL(){
return url;
}
}
Enums cannot be extended in such a manner, mostly because enums cannot be sub-classed or the constraints they must adhere to will not be possible to impose.
Instead leverage interfaces, like so
public interface IEndPoint;
public enum DefaultEndPoints implements IEndPoint {
NA_END_POINT,
EU_END_POINT,
JP_END_POINT,
CN_END_POINT,
}
public enum DefaultServiceEndPoints implements IEndPoint {
NA_END_POINT("http://A.com/");
EU_END_POINT("http://A-eu.com/");
JP_END_POINT("http://A-jp.com/");
CN_END_POINT("http://A-cn.com/");
}
public void doSomething(IEndPoint endpoint) {
...
}
The reason why one can't subclass in the manner you wish is related to the contract that enums will be both equal via .equals(object) and via ==. If you could subclass, would this make sense?
if ( (DefaultEndPoints)JP_END_POINT == (DefaultServiceEndPoints)JP_END_POINT) {
}
if you say "yes" then I would expect to be able to do this
DefaultEndPoint someEndpoint = DefaultServiceEndPoints.JP_END_POINT;
which would leave a door open for error, as there is no guarantee that a enum entry in one enum declaration is in the other enum declaration.
Could it be different? Perhaps, but it isn't, and changing it would definately introduce a lot of complications that would have to be thoroughly thought out (or it would open avenues to work around Java's strong static-type checking).
You may want to consider something like this:
public abstract class EndpointFactory {
public abstract String getNAEndPoint();
public abstract String getEUEndPoint();
}
public class ServiceAEndpointFactory extends EndpointFactory {
public static final String NA_END_POINT = "http://A.com/";
public static final String EU_END_POINT = "http://A-eu.com/";
public String getNAEndPoint() {
return ServiceAEndpointFactory.NA_END_POINT;
}
public String getEUEndPoint() {
return ServiceAEndpointFactory.EU_END_POINT;
}
}
public class ServiceBEndpointFactory extends EndpointFactory {
public static final String NA_END_POINT = "http://B.com/";
public static final String EU_END_POINT = "http://B-eu.com/";
public String getNAEndPoint() {
return ServiceAEndpointFactory.NA_END_POINT;
}
public String getEUEndPoint() {
return ServiceAEndpointFactory.EU_END_POINT;
}
}
Then you can refer to your strings directly like this:
ServiceAEndpointFactory.NA_END_POINT;
Or, you can use the base object if the type of service is not known until execution:
EndpointFactory ef1 = new ServiceAEndpointFactory();
String ep = ef1.getNAEndPoint();
The drawback of this is the redefinition of the get*Endpoint() functions in each sub-class. You could eliminate that by moving the static final variables to be not static in the base class and putting the getter/setter in the base class only one time. However, the drawback of that is you are not able to reference the values without instantiating an object (which essentially emulates what I find valuable with ENUMs).
How does a pattern like this appeal to you? I let the enum implement an interface and implement the interface in a Debug set and a Release set. The release set can then derive the property name from the enum name - which is neat.
public interface HasURL {
public String getURL();
}
public enum DebugEndPoints implements HasURL {
NA,
EU,
JP,
CN;
#Override
public String getURL() {
// Force debug to go to the same one always.
return "http://Debug.com/";
}
}
public enum NormalEndPoints implements HasURL {
NA,
EU,
JP,
CN;
final String url;
NormalEndPoints () {
// Grab the configured property connected to my name.
this.url = getProperty(this.name());
}
#Override
public String getURL() {
return url;
}
}
I am working on a component which is supposed to:
receive data (collection of items) from some external calculation component. I expect about 100-1K of items on input on each request.
validate data, calculate some attributes if missing
persist data
There are about ten types of items. I use inheritance to model items. I have a base item class with common attributes and calculations and subclasses implementing type specific problems. Similar to following example:
public abstract class BaseItem {
String name;
boolean valid = true;
public void postCalucate() {
//common calculation
valid = valid && (name != null);
}
}
public class ItemA extends BaseItem {
BigDecimal value;
#Override
public void postCalucate() {
//some A specific calculations
super.postCalucate();
}
}
public class ItemA1 extends ItemA {
BigDecimal extraValue;
#Override
public void postCalucate() {
//some A1 subtype specific calculations
valid = isA1ItemValid();
super.postCalucate();
}
}
public class ItemB extends BaseItem {
Integer size;
#Override
public void postCalucate() {
//some B specific calculations
super.postCalucate();
}
}
Is there any better way/pattern to do my task? Any advices?
The pattern you are trying to use is fairly sound. In general, I would probably suggest the use of an interface instead of a BaseItem class, since it might not contain that much common functionality.
In general, most people seem to recommend defining interfaces for your classes to implement. If absolutely you want to share common code in an AbstractClass, I would recommend that class implementing the interface, since this pattern would lend itself to greater extensibility and flexibility in the future.
As such, you would first begin by defining what an Item is for you. For me, it seems that an Item is three things in your use case: one, it must define the postCalculate() method that will be called on all Items. Second, it must provide an isValid() method. And third, it should also provide a getName() method.
public interface Item {
void postCalucate();
boolean isValid();
String getName();
}
Then you would begin implementing your Abstract class. Do this only if it really is necessary to share a codebase between all your items.
public abstract class BaseItem implements Item {
String name;
boolean valid = true;
public void postCalucate() {
//common calculation
valid = valid && (name != null);
}
public boolean isValid() {
return valid;
}
public String getName() {
return name;
}
}
If BaseItem.postCalculate() is something that will need to be done for all items, this is a good way to do it. If you're not entirely sure, it might be a good idea instead to define a method somewhere in a Helper or Tool class that performs this common calculation for items, and is called by the postCalculate() methods:
public class ItemTools {
public static boolean meetsRequirements(Item item) {
return item.isValid && item.getName() != null;
}
}
This, many would argue, gives you an easier time as your requirements on BaseItem may change over time.
Regardless of which route you go there, now you'll just have to define your actual items:
public class ItemA extends BaseItem {
BigDecimal value;
#Override
public void postCalucate() {
//some A specific calculations
super.postCalucate();
}
}
While the general advice is to avoid over-usage of inheritance, this is no case of over-usage. So, go ahead with this approach.
Apart from that: Your code shows problems with encapsulation. You shouldn’t have all these non-private field. As a reminder: no visibility at all is package-visibility (visible in the whole package and to all sub-classes). Make your fields private.
A priori, your proposal seems reasonable.
But to be sure, you have to look at all the events of the life cycle of your objects:
instantiation
use, read
collaboration
persistence
...