So, I've been working on some playing cards in Java. (Not for any practical purpose really, I just enjoy playing cards and they're good practice) Now, right now, I'm making some Card Structures, decks, hands, piles, etc. They're all essentially the same, so I figure that I'd like to use some inheritance.
The problem that I've encountered is that the core of each structure is some type of collection, but they don't all use the same collection type. A deck uses a Stack, since a deck essentially functions as a stack most often. But, a hand uses an ArrayList (If there is something more efficient than an ArrayList to use, that would be good to know as well).
So, when trying to write an abstract class, I'd like to avoid using abstract methods (as it defeats the original purpose of making an abstract class, to conserve code). But, all of these methods rely on the core collection, for obvious reasons, but I don't know what type the collection is. This is what I've tried so far:
public abstract class CardSet
{
protected AbstractCollection<Card> elCollection;
public CardSet()
{
super();
}
public CardSet(Card[] cards)
{
super();
for(Card c: cards)
elCollection.add(c);
}
public void add(Card c)
{
elCollection.add(c);
}
}
public class Pair extends CardSet //Pair is just a dummy class to get inheritance right
{
ArrayList<Card> elPair;
public Pair()
{
elPair = new ArrayList<Card>(); //elPair is defined, because casting
elCollection = elPair; // elCollection to arraylist would be a pain.
}
public Pair(Card[] cards)
{ this();
super(cards);
}
}
First off, forgive my variable names. I used to name everything "theVariable", but I decided that using "el" was more interesting. (You've got to amuse yourself somehow, right?) Also, using protected was just for the sake of simplicity.
Now, the general idea seems to work, defining a variable in the abstract class, and then defining an alias of it in the child class, but I'm not so sure that it's a great practice.
The real problem I'm having is with the constructor. The constructor in Pair that accepts an array of Cards doesn't work, because to add the cards, I would first need to create the
collection (in this case, the ArrayList) before the parent constructor tries to add the cards.
Is there any way to work around this? Is this even a viable way of handling inheritance?
I think your biggest problem is that your just creating these classes without any real requirements. Is inheritance really the right choice here? It feels like you're designing the classes to fit a pre-conceived implementation instead of the other way around.
Define your interfaces for each class you need based on the real requirements, implement them, and then see if an abstract base class makes sense.
Just have each implementation pass down the collection type in the constructor:
public abstract class CardSet<C extends Collection<Card>>
{
protected final C elCollection;
public CardSet<Collection<Card>> cardSet()
{
return new CardSet<Collection<Card>>(new ArrayList<Card>());
}
public CardSet(C col){
this.elCollection = col;
}
public CardSet(C col, Card[] cards)
{
this(col);
for(Card c: cards)
elCollection.add(c);
}
public void add(Card c)
{
elCollection.add(c);
}
}
public class Pair extends CardSet<List<Card>>
{
public Pair()
{
super(new ArrayList<Card>());
}
public Pair(Card[] cards)
{
super(new ArrayList<Card>(), cards);
}
}
You may have to play a little bit with the declarations, but that should see you right
I'll give a quick (hackish?) answer: something you could do is have a protected abstract Collection<Card> createCollection() method defined in the base class, CardSet. Your subclasses would override this to create and return whatever type of collection is appropriate for that subclass. Then the superclass constructor would use that method to create the collection, after which it could go ahead and add the cards:
public CardSet(Card[] cards) {
super();
self.elCollection = createCollection();
Collections.addAll(self.elCollection, cards);
}
My feeling here is that you're trying to do 2 separate things with inheritance, so it seems confusing -
On the one hand, you have the concept of a set of cards. This will have a collection of cards. So first we know we have this:
public abstract class CardSet {
protected Collection<Card> cards;
}
At this point your classes should diverge, because what we have so far is the extent of the common behavior (well, we'll probably have some additional methods in there, like size(), nextCard(), isEmpty(), etc etc, that are easy enough to define on the protected collection, but never mind those now).
To use your own example
public class Deck extends CardSet {
public Deck (){
cards = new Stack<Card>();
}
public void shuffle() { ... }
}
public class Hand extends CardSet {
public Hand(){
//i'm using a set here instead of the list in your example because I
// don't think ordering is a property of a hand.
cards = new HashSet<Card>();
}
}
public class Pair extends CardSet {
...
}
Here cardSets are of different kinds. Thery're separated because they're expected to behave differently, and represent the additional behavior these types of collections have from the generalized notion of a card set. Trying to shoehorn additional code into the abstract parent may save a few lines but ultimately obfusactes.
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.
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.
Ok a fairly difficult Question to phrase but this is the best I can come up with.
Basically I have an Animal Class, an Insect Class which inherits from the Animal Class, and a Spider, Woodlouse and Worm class which inherit from the Insect Class
Say for example I have a class called InsectStorage which defines and stores a number of Insect objects in an array (so an array of different species of worms, woodlouses etc). And I want the user to be able to select an insect and have an insect assigned for the player within this class.
Setting the insect is achievable enough with
Spider blackWidow = new Spider()
Spider wolfSpider = new Spider()
Spider[] spiderStorage = new Spider[2]
worm lumbricusTerrestris = new Worm()
...
switch (insectSelect)
case: "Black Widow"
So the switch statement is where the first complication arises but is just about solvable by creating a selectedPlayerInsect of type Worm, Spider and Woodlouses and setting each one based on selection.
But how could I possibly create a getPlayerInsect() method? I would need to be able to return a Spider if a spider is selected, and a Worm if a worm is selected.
I could try making a playerObject for each insect subclass and creating four getPlayerXX() methods but that would mean every time I wanted to call getPlayerSpider() or getPlayerWorm() within my main method I would have to put if statements in to check which object had been selected (which would be highly inconvenient).
I tried fiddling around with Wrapper classes but couldn't make those work either (as I would still to use if playerIsWorm etc).
Alot of text, not much code, but I dont think code is really needed with my explanation.
How can I (if I can) solve this Issue?
So the way to solve your problem immediately is by doing type checking - basically what you said. It's ugly, but based on what you have in mind it works.
However, I think there is a deeper problem to think about.
If you design your classes properly, the actual 'type' of the Insect class shouldn't matter. You should build the different logic into the subclasses themselves. This makes it easier to build on top in the future. #PM 77-1 said it best - you need to use polymorphism the way it should be used.
So instead, just have:
public Insect getPlayerInsect(){
return playerInsect;
}
Maybe your main method looks something like this:
Insect player = getPlayerInsect();
player.eat(); // Everything eats
You don't need (shouldn't) to build complicated if/else logic into that eat statement.
abstract class Insect {
abstract void eat();
}
class Spider extends Insect{
#Override
public void eat(){
//eat dung
}
}
class Worm extends Insect {
#Override
public void eat(){
//eat soil
}
}
You delay the decision making until the very end - until the method actually gets called. This way you reuse functionality and don't need to write lots of complicated if/else statements.
If you need to add other functionality to your insect player object, you just add them and override them appropriately.
If you find that eat doesn't apply to all subclasses, then it usually means you need to remodel your class hierarchy.
I'm not sure if you want the "player" to be able to select the type of insect OBJECT (woodlouse, worm, spider) or the type of insect 'name' (for lack of a better term - Blackwidow, wolfspider,etc).
If the former, it seems you could utilize the getClass() method (http://www.tutorialspoint.com/java/lang/object_getclass.htm) and compare that with your known classes in an enumerated list when creating the new insect for the player.
If the latter, eckes's answer seems to be appropriate.
You can uses Clases/Enums for the different types of insects.
Enum Spiders {BLACKWIDOW, WOLFSPIDER};
Spider firstSpider = Spiders.BLACKWIDOW;
if (firstSpider == Spiders.BLACKWIDOW) ...
vs.
class BlackWidow extends Spider {... }
class WolfSpider extends Spider { ... }
Spider firstSpider = new BlackWidow();
if (firstSpider instanceof BlackWidow) ....
In that case you would test with instanceof or .class (for the Class case) or == for the Enum case. In your case when you have one class Spider you should give it a property with its name:
Spider blackWidow = new Spider("BlackWidow");
if (blackWidow.isType("BlackWidow)) ...
There would be a possibility to check for known instances with the == operator. But this is bad practice for actual domain classifications and hard to debug (and does not work with persisted identities):
public class Spiders {
final Spider BLACKWIDOW = new Spider();
final Spider WOLFSPIDER = new Spider();
void doSpiderThing(Spider userSelection) {
if (userSelection == BLACKWIDOW) {
...
void selectSpiderByName(String spiderName) {
if ("Tekla".equals(spiderName))
doSpiderThing(BLACKWIDOW);
...
Or similiar. You asked in comments how you can return spider or work, you would do that by returning a super-type of both (by default Object, but better something specific):
interface Animal {String getSpecies(); }
Enum AnimalEnum implements Animal {
BLACKWIDOW { getSpecies() {return "Spider"; }},
WOLFSPIDER { getSpecies() {return "Spider"; }},
WORM { getSpecies() {return "Worm"; }}
}
Animal getAnimalBySelection(String input) {
if ("worm".equalsIgnoreCase(input))
return AnimalEnum.WORM;
else ...
}
I have the following classes
class Person {
private String name;
void getName(){...}}
class Student extends Person{
String class;
void getClass(){...}
}
class Teacher extends Person{
String experience;
void getExperience(){...}
}
This is just a simplified version of my actual schema. Initially I don't know the type of person that needs to be created, so the function that handles the creation of these objects takes the general Person object as a parameter.
void calculate(Person p){...}
Now I want to access the methods of the child classes using this parent class object. I also need to access parent class methods from time to time so I CANNOT MAKE IT ABSTRACT.
I guess I simplified too much in the above example, so here goes , this is the actual structure.
class Question {
// private attributes
:
private QuestionOption option;
// getters and setters for private attributes
:
public QuestionOption getOption(){...}
}
class QuestionOption{
....
}
class ChoiceQuestionOption extends QuestionOption{
private boolean allowMultiple;
public boolean getMultiple(){...}
}
class Survey{
void renderSurvey(Question q) {
/*
Depending on the type of question (choice, dropdwn or other, I have to render
the question on the UI. The class that calls this doesnt have compile time
knowledge of the type of question that is going to be rendered. Each question
type has its own rendering function. If this is for choice , I need to access
its functions using q.
*/
if(q.getOption().getMultiple())
{...}
}
}
The if statement says "cannot find getMultiple for QuestionOption." OuestionOption has many more child classes that have different types of methods that are not common among the children (getMultiple is not common among the children)
NOTE: Though this is possible, it is not at all recommended as it kind of destroys the reason for inheritance. The best way would be to restructure your application design so that there are NO parent to child dependencies. A parent should not ever need to know its children or their capabilities.
However.. you should be able to do it like:
void calculate(Person p) {
((Student)p).method();
}
a safe way would be:
void calculate(Person p) {
if(p instanceof Student) ((Student)p).method();
}
A parent class should not have knowledge of child classes. You can implement a method calculate() and override it in every subclass:
class Person {
String name;
void getName(){...}
void calculate();
}
and then
class Student extends Person{
String class;
void getClass(){...}
#Override
void calculate() {
// do something with a Student
}
}
and
class Teacher extends Person{
String experience;
void getExperience(){...}
#Override
void calculate() {
// do something with a Teacher
}
}
By the way. Your statement about abstract classes is confusing. You can call methods defined in an abstract class, but of course only of instances of subclasses.
In your example you can make Person abstract and the use getName() on instanced of Student and Teacher.
Many of the answers here are suggesting implementing variant types using "Classical Object-Oriented Decomposition". That is, anything which might be needed on one of the variants has to be declared at the base of the hierarchy. I submit that this is a type-safe, but often very bad, approach. You either end up exposing all internal properties of all the different variants (most of which are "invalid" for each particular variant) or you end up cluttering the API of the hierarchy with tons of procedural methods (which means you have to recompile every time a new procedure is dreamed up).
I hesitate to do this, but here is a shameless plug for a blog post I wrote that outlines about 8 ways to do variant types in Java. They all suck, because Java sucks at variant types. So far the only JVM language that gets it right is Scala.
http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html
The Scala creators actually wrote a paper about three of the eight ways. If I can track it down, I'll update this answer with a link.
UPDATE: found it here.
Why don't you just write an empty method in Person and override it in the children classes? And call it, when it needs to be:
void caluculate(Person p){
p.dotheCalculate();
}
This would mean you have to have the same method in both children classes, but i don't see why this would be a problem at all.
I had the same situation and I found a way around with a bit of engineering as follows - -
You have to have your method in parent class without any parameter and use - -
Class<? extends Person> cl = this.getClass(); // inside parent class
Now, with 'cl' you can access all child class fields with their name and initialized values by using - -
cl.getDeclaredFields(); cl.getField("myfield"); // and many more
In this situation your 'this' pointer will reference your child class object if you are calling parent method through your child class object.
Another thing you might need to use is Object obj = cl.newInstance();
Let me know if still you got stucked somewhere.
class Car extends Vehicle {
protected int numberOfSeats = 1;
public int getNumberOfSeats() {
return this.numberOfSeats;
}
public void printNumberOfSeats() {
// return this.numberOfSeats;
System.out.println(numberOfSeats);
}
}
//Parent class
class Vehicle {
protected String licensePlate = null;
public void setLicensePlate(String license) {
this.licensePlate = license;
System.out.println(licensePlate);
}
public static void main(String []args) {
Vehicle c = new Vehicle();
c.setLicensePlate("LASKF12341");
//Used downcasting to call the child method from the parent class.
//Downcasting = It’s the casting from a superclass to a subclass.
Vehicle d = new Car();
((Car) d).printNumberOfSeats();
}
}
One possible solution can be
class Survey{
void renderSurvey(Question q) {
/*
Depending on the type of question (choice, dropdwn or other, I have to render
the question on the UI. The class that calls this doesnt have compile time
knowledge of the type of question that is going to be rendered. Each question
type has its own rendering function. If this is for choice , I need to access
its functions using q.
*/
if(q.getOption() instanceof ChoiceQuestionOption)
{
ChoiceQuestionOption choiceQuestion = (ChoiceQuestionOption)q.getOption();
boolean result = choiceQuestion.getMultiple();
//do something with result......
}
}
}
Sorry for the poor title, can't think of a succinct way of putting this..
I'm thinking of having a list of objects that will all be of a specific interface. Each of these objects may then implement further interfaces, but there is no guarantee which object will implement which. However, in a single loop, I wish to be able to call the methods of whatever their further sub-type may be.
Ie, 3 interfaces:
public interface IAnimal { ... }
public interface IEggLayer { public Egg layEgg(); }
public interface IMammal { public void sweat(); }
this would then be stored as
private List<IAnimal> animals= new ArrayList<IAnimal>();
so, instances added to the list could possibly also be of type IEggLayer or IMammal, which have completely unrelated methods.
My initial instinct would be to then do
for(IAnimal animal : animals) {
if(animal instanceof IEggLayer) {
egg = ((IEggLayer)animal).layEgg();
}
if(animal instance of IMammal) {
((IMammal)animal).sweat();
}
}
But I have always been told that type checking is a sign that the code should really be refactored.
Since it could be possible for a single object to do both [platypus, for example], meaning that a single doFunction() would not be suitable here, is it possible to avoid using type checking in this case, or is this an instance where type checking is classed as acceptable?
Is there possibly a design pattern catered to this?
I apologise for the contrived example as well...
[Ignore any syntax errors, please - it's only intended to be Java-like pseudocode]
I've added lvalue to the EggLayer use, to show that sometimes the return type is important
Clearly your IAnimal interface (or some extension thereof) needs a callAllMethods method that each implementer of the interface can code to polymorphically perform this task -- seems the only OO-sound approach!
But I have always been told that type checking is a sign that the code should really be refactored.
It is a sign that either class hierarchy or the code that uses it may need to be refactored or restructured. But often there will be no refactoring / restructuring that avoids the problem.
In this case, where you have methods that apply only to specific subtypes, the most promising refactor would be to have separate lists for the animals that are egg layers and the animals that sweat.
But if you cannot do that, you will need to do some type checking. Even the isEggLayer() / isMammal() involves a type check; e.g.
if (x.isEggLayer()) {
((IEggLayer) x).layEgg(); // type cast is required.
}
I suppose that you could hide the type check via an asEggLayer() method; e.g.
public IEggLayer asEggLayer() {
return ((IEggLayer) this);
}
or
// Not recommended ...
public IEggLayer asEggLayer() {
return (this instanceof IEggLayer) ? ((IEggLayer) this) : null;
}
But there is always a typecheck happening, and the possibility that it will fail. Furthermore, all of these attempts to hide the type checking entail adding "knowledge" of the subtypes to the supertype interface, which means that it needs to be changed as new subtypes are added.
in C#, you should be able to do this transparently.
foreach(IEggLayer egglayer in animals) {
egglayer.layEgg();
}
foreach(IMammal mammal in animals) {
mammal.sweat();
}
I think the way to think about this question is: What is the loop doing? The loop has a purpose and is trying to do something with those objects. That something can have a method on the IAnimal interface, and the implementations can sweat or lay eggs as needed.
In terms of your issue with the return value, you will be returning null, nothing you can do about that if you share the methods. It is not worth casting within a loop to avoid an extra return null; to satisfy the compiler. You can, however, make it more explicit using generics:
public interface IAnimal<R> {
public R generalMethod();
}
public interface IEggLayer extends IAnimal<Egg> {
public Egg generalMethod(); //not necessary, but the point is it works.
}
public interface IMammal extends IAnimal<Void> {
public Void generalMethod();
}
From your comment where you care about the return type, you can get the return type and dispatch it to a factory method which examines the type and returns something generic that is sublcassed to the specific type and act on that.
Why not have methods added to isAnimal:
public interface IAnimal {
bool isEggLayer();
bool isMammal();
}
Then you can loop through and just query this boolean each time.
Update:
If this was drawing an animal, then having a class that is completely enclosed is reasonable, you just call drawVehicle and it draws a corvette, cessna, motorcycle, whatever.
But, this seems to have a non-OOP architecture, so if the architecture of the application can't change then, since my original answer isn't well received, then it would seem that AOP would be the best choice.
If you put an annotation on each class, you can have
#IsEggLayer
#IsMammal
public class Platypus() implements EggLayer, Mammal {
...
}
This would then enable you to create aspects that pull out all the egglayers and do whatever operations need to be done.
You can also inject into the animal interfaces any additional classes to get this idea to work.
I will need to think about where to go from here, but I have a feeling this may be the best solution, if a redesign can't be done.
There are many ways of going about this. Exaclty which is most appropriate depends upon your context. I am going to suggest introducing an additional layer of indirection. This solves most problems. I prefer designs which avoid multiple inheritance of interface (if I were president of a language, I would forbid it).
I don't think layEggsOrSweatOrDoBothIfYoureWeirdOrNoneIfYouCant() is a great method to polute Animal with. So instead of adding each Animal directly to animals, wrap each in an individual wrapper. I say "wrapper" as a generic name - the random operation we are trying to perform doesn't make any sense.
private final List<AnimalWrapper> animals =
new ArrayList<AnimalWrapper>();
public void doStuff() {
for (AnimalWrapper animal : animals) {
animal.doStuff();
}
}
Then we need some way of adding the wrappers. Something like:
public void addPlatypus(final Platypus platypus) {
animals.add(new AnimalWrapper() { public void doYourStuff() {
platypus.sweat();
platypus.layEgg();
}});
}
If you try to write these wrappers without enough context you get into trouble. These require that the correct one is selected at call site. It could be done by overloading, but that has dangers.
/*** Poor context -> trouble ***/
public void addNormalMamal(final Mamal mamal) {
animals.add(new AnimalWrapper() { public void doYourStuff() {
mamal.sweat();
}});
}
public void addNormalEggLayer(final EggLayer eggLayer) {
animals.add(new AnimalWrapper() { public void doYourStuff() {
eggLayer.layEgg();
}});
}
public <T extends Mamal & EggLayer> void addMamalEggLayer(final T animal) {
animals.add(new AnimalWrapper() { public void doYourStuff() {
animal.sweat();
animal.layEgg();
}});
}