I have two abstract classes: Char and Weapon. Each has two derivative classes: King and Troll, and Club and Sword.
A character always has a weapon, but the type is not specified. So when building the Char class I cannot initialise the correct type. Also, when choosing a character, I similarly cannot initialise the correct type.
Is it wrong to initialise an abstract class? How can one initialise a class of one sort and then change the variable class? Provided the new type is a trivially different inheritation of the same parent class? Or should one go about it completely differently?
It may very well be that I haven't even understood the concept of an abstract class. I'm new to Java and pure OOP.
public class Player{
private Char c; // Wrong?
public void changeChar(int charID, int wepID){
switch(charID){
case 1: c = new King(wepID); break;
case 2: c = new Troll(wepID); break;
}
}
public void fight(){
c.fight();
}
}
abstract class Char{
protected String name;
public Weapon weapon; // Wrong?
Char(int wepID){
switch(wepID){
case 1: weapon = new Sword(); break;
case 2: weapon = new Club(); break;
}
}
public void fight(){
weapon.useWeapon(name);
}
}
abstract class Weapon{
protected String wepName;
public void useWeapon(String user){
System.out.println(user + " fights with " + wepName);
}
}
class Club extends Weapon{
Club(){
wepName = "Club";
}
}
class Sword extends Weapon{
Sword(){
wepName = "Sword";
}
}
class Troll extends Char{
Troll(int wepID){
super(wepID);
name = "Troll";
}
}
class King extends Char{
King(int wepID){
super(wepID);
name = "King";
}
}
You cannot instantiate an abstract class. A smarter way to go is to provide your constructor for Char a Weapon instance as a parameter - you could simply use it in Char.
abstract class Char{
protected String name;
public Weapon weapon;
Char(Weapon weapon){
this.weapon = weapon;
}
public void fight(){
weapon.useWeapon(name);
}
}
class Troll extends Char{
Troll(Weapon weapon){
super(weapon);
name = "Troll";
}
}
and later in your code:
Char troll = new Troll (new Club());
In Java, abstract classes are allowed to have one or more methods that are specified, but not implemented. They are meant to be used as "the highest common denominator" for subclasses that share majority of functionality, except a few methods. Therefore, Java prohibits you from creating an instance of an abstract class, and requires any subclass to provide implementations of abstract methods. This is by design. The basic idea behind it is to promote code reusability, but in real life, it's a mix of trade-offs so your mileage might vary. Most of the time, you can achieve a similar effect with a combination of non-abstract base classes and interfaces.
Based on your example, Char does not have to be an abstract class, but Weapon is a good candidate because it has a "useWeapon" method. You can declare "useWeapon" as abstract in Weapon, and provide different implementations in Sword and Club. Alternatively, you could make a Weapon an interface. The abstraction you want to make here is that a Char can use a Weapon without knowing whethere the actual weapon is a Club or Sword. This means you can give a Char anytime a weapon of any kind, and everything should work. Instead of passing a Char an "int" in constructor, it's actually better to pass it the Weapon itself.
Related
My main question is if I can bind a generic object two 2 types if the it is extended by e.g. 4 types. I do not really know how to ask this question without an example.
So i created a little example of a simple game in which Warriors or Rangers can equip different type of Weapons(OneHanded, TwoHanded, Melee, Ranged). Every Weapon has two attributes. So the e.g. the Weapon type Dagger extends Weapon implements OneHanded, Melee.
Ranger class (can use two-handed, ranged Weapons):
private Weapon weapon;
public <T extends TwoHanded & Ranged> void equip(T weapon) {
this.weapon = (Weapon) weapon;
}
Warrior class (can use one-handed, two-handed, melee, ranged weapons):
private Weapon weapon;
public <T extends OneHanded & Melee & Ranged> void equip(T weapon) { //probably have to do this differently
this.weapon = (Weapon) weapon;
}
Bow and Dagger class:
public class Bow extends Weapon implements TwoHanded, Ranged {}
public class Dagger extends Weapon implements OneHanded, Melee {}
public void equipTest() {
ranger.equip(bow); //works fine
warrior.equip(dagger); //does not work
}
The main problem here is (I think) that I do not know how to implement it that a warrior can equip different weapons with different attributes(e.g. bow(ranged, two-handed) or also dagger(melee, one-handed)) whereas the ranger has only one possibility. How can I workaround this problem?
The code does not compile because Dagger does not implement Ranged.
I think you mean Melee or Ranged. This could be written as overloads.
<T extends Melee & OneHanded> void equip(T weapon) {
<T extends Ranged & OneHanded> void equip(T weapon) {
Note change of order in order for the overload to have distinct erasures. However, it is much better to have distinct names rather than overload.
(Also, I'd use a layer of indirection instead of losing the type information with a base type.)
The other answer directly addresses the issue in the question. As you can see, using this design, the best option for you is to end up with a bunch of equipXXX() methods.
An alternative would be to use the decorator pattern.
Create abstract Weapon and WeaponDecorator to allow maximum flexibility for later adding new weapon types.
public abstract class Weapon {
...
}
public abstract class WeaponDecorator extends Weapon {
Weapon _weapon;
WeaponDecorator(Weapon weapon) {this._weapon = weapon;}
}
Convert various weapon types to act as weapon decorators:
public class OneHanded extends WeaponDecorator {
OneHanded(Weapon weapon) {
super(weapon);
}
}
public class Melee extends WeaponDecorator {
Melee(Weapon weapon) {
super(weapon);
}
}
and remove all generics from the Warrior class too:
public class Warrior {
private Weapon weapon;
public void equip(Weapon weapon) {
this.weapon = weapon;
}
}
Now you can simply do:
Weapon w = new OneHanded(new Melee(new Dagger()));
Warrior warrior = new Warrior();
warrior.equip(w);
Here is a full example with code and more explanation.
EDIT:
If you choose this solution, the responsibility of checking the validity of selected weapon for a selected hero should also be addressed in run time. For example, this can be added to Ranger's equip method:
if(weapon.isMelee()) //error (unacceptable)
But as the set of rules grow complex, you might want to use other patterns such as the command pattern. Still, all of this will be delegated to run time. This is the price that you pay for acquiring more flexibility. Of course, you can also try to acquire some compile-time safety by creating a hierarchy of decorators (similar to what java.io library does). However, this could make the application overly complicated very fast.
In the end, if there are only a few of this combined types (TwoHanded + Melee, OneHanded + Ranged, etc) it makes sense to go with the other answer and just have a few more equip methods and have the safety of compile time type checking.
I was reading Eric Lippert blog about Wizards and Warriors. Interesting read, but I found certain parts hard to understand (not the authors fault, I'm only a beginner in OOP).
He presents the problem of two character types within a game, a Wizard and a Warrior, and the rules are:
A warrior can only use a sword.
A wizard can only use a staff
In the blog, he uses a getter/setter in the first part to handle the weapon for the character, but let's change it to an inventory system. So, we have an abstract class called Player with a list of items(ArrayList).
interface Weapon {
attack(Enemy enemy);
}
public class Staff implements Weapon {}
public abstract class Player {
private List<Weapon> weaponInventory;
//left out constructor and other methods to keep it on point
abstract void add(Weapon add)
}
and use it like so:
public class Wizard extends Player {
#Override
public void add(Weapon add){
//code to add weapon;
}
}
How would you structure the add method to enforce the rule that a Wizard can only use a staff? I thought of calling getClass() or getType() on weapon but those are considered bad practice.
The best answer I could come up with was have a String variable called type, and a getter in the Weapon interface. During object construction, set the type to sword or staff. However, this doesn't really help, as you could create a sword object, pass in staff as the type, and use it.
How would you prevent a sword from being added to the wizards inventory?
How would you structure the add method to enforce the rule that a Wizard can only use a staff?
Either you didn't read the whole series, or you didn't understand its central message. The entire point of that series of articles is to express that there is no good way to structure a method that enforces a restriction on the relationship between subclasses.
This is simply a fact about subclass-based OOP; there are some things it does not model well, and this is one of them. A fundamental principle of many OOP type systems, including that of Java and C#, is Liskov's: that you can always use an instance of a subclass where an instance of a superclass is needed. That makes modeling restrictions in the type system difficult.
In the last part of the series I give the best solution that I know of: model the rules of the simulation as objects themselves, and have a rule enforcer class that gives the user feedback when they attempt to violate a rule. Don't make the type system try to solve your business problems.
You could use something like the following. Note: in the Player class, the weapons can be of any type. However each sub-class of player has its own specific add(). So while this approach enforces the required rules, it loses a little generality.
public class Staff implements Weapon {}
public class Sword implements Weapon {}
public abstract class Player {
private List<Weapon> weaponInventory;
protected final void addWeapon(Weapon weapon) {
weaponInventory.add(weapon)
}
}
public class Wizard extends Player {
public void add(Staff staff) {
addWeapon(staff);
}
}
public class Warrior extends Player {
public void add(Sword sword) {
addWeapon(sword);
}
}
You could use generics:
Weapon and Staff classes remain the same:
public interface Weapon {
void attack(Enemy enemy);
}
public class Staff implements Weapon {
#Override
public void attack(Enemy enemy) {
//Do ur attacking. :)
}
}
The Player class has a generic type:
import java.util.ArrayList;
import java.util.List;
public abstract class Player<T extends Weapon> {
protected List<T> weaponInventory = new ArrayList<>();//Made protected so Wizard can access it.
public abstract void add(T weapon);
}
And the Wizard class extends Player<Staff> (NOT just Player):
public class Wizard extends Player<Staff> {
#Override
public void add(Staff weapon) {
// Add the staff to the list declared in Player
weaponInventory.add(weapon);
}
}
Explanation:
The T in Player<T> is the type of weapon that you want the player to use.
When you extend Player<Staff> in the Wizard class, you're saying that you want Wizard to be a Player that only uses Staffs. This way, the Wizard's weaponInventory list will contain only Staffs.
When you add the Warrior class, it would extend Player<Sword>, which would make its weaponInventory only take Swords.
By the way, I instantiated weaponInventory in the above code and implemented the add method in Wizard.
Java - Is it possible to extend all the subclasses of a class with a single class?
Let's explain it with an example, the actual code is quite more complex. I have an Animal class with its own class hierarchy. Let's say that it has two subclasses: Testarrosa and Viper.
public class Car {
public abstract String getManufacturer();
}
public class Testarossa extends Car{
public String getManufacturer(){
return "Ferrari";
}
}
public class Viper extends Car{
public String getManufacturer(){
return "Dodge";
}
}
I want to extend all the Car subclasses with a RegisteredCar subclass.
public class RegisteredCar extends Car {
private String plateNumber;
public RegisteredCar (String plateNumber){
this.plateNumber=plateNumber;
}
public String getPlateNumber() {
return plateNumber;
}
}
At some point, I should be able to create a new RegisteredCar of a specific subclass. Something like
RegisteredCar c = new RegisteredCar<Viper>("B-3956-AC");
And call the c.getManufacturer() to obtain "Dodge" and c.getPlateNumber() to obtain B-3956-AC. Obviously, I should still be able to create a Car c = new Viper();
That is an example. Having an attribute in Car with null value if not registered is not enough for what I need.
In short, no that is not possible. You have to unfortunately modify your object model.
For example, what about having a Registration class this way:
public interface Registration<C extends Car> {
C getCar();
String getPlateNumber();
}
This way you can extract the information relating to registration in a single class, while maintaining your Car models.
You can then do helper methods like:
Registration<Viper> registeredViper = createRegistration(new Viper(), "B-3956-AC");
As others have said, no thats not really possible and your example could be solved by changing your model
As an alternative to inheritance you could use another class to wrap a Car instance.
I would make Car an interface (though having RegisteredCar extend Car should work too) and then attempt something like the following pseudo code:
class RegisteredCar<T extends Car> implements Car {
private final T car
RegisteredCar(T car) {
this.car = car;
}
... methods for RegisteredCar
... methods from Car delegating to `this.car`
}
Please excuse the somewhat bad code, I don't have an IDE open, and I always mess up generics without an IDE to hand.
Another possible solution is to use AOP, though I don't know how in fashion that is these days as but what you are describing could be a cross cutting concern.
A final alternative might be to use a language that allows for Extensions, Traits, Protocol or some other type of 'mix in'
In java it is prohibited to extends more than 1 class.
You could build chain from classes to extends, for example.
To solve the problem of mutiple inheritance in Java → interface is used
You should avoid inheritance as much as possible. Use abstractions (interfaces) to make your code elegant and maintainable. Just google why extends is evil.
public interface Car{
String getManufacturer();
}
public interface Registerable{
boolean isRegistered();
void register(String plateNumber);
void getPlateNumber();
}
public class Viper implements Car, Registerable
{
//all methods
}
With Generic class approach as described in other answer, you will not be able to use RegisteredCar where your require to pass Car object. e.g. suppose you need to generate some invoice.
Invoice getInvoice(Car c);
In this method you cannot use RegisteredCar as it is not of Type Car. All you API which require Car are not applicable to RegisteredCar. In some cases you may need Plate Number as well as Car, There you may need to keep mapping of Plate Number and Cars. I would suggest following approach based on Decorate Pattern and delegate all Car calls to passed car object
public class RegisteredCar extends Car{
public RegisteredCar(Car c, String plateNumber){
}
#Override
String getColor(){
c.getColor();
}
}
No, it's not like C++. Multiple inheritance is not possible in Java. However you can implement multiple interfaces.
You cannot achieve that with inheritance.
Your best option is making the RegisteredCar type generic, then having a generic instance variable that holds the intended type car:
public class RegisteredCar<T extends Car> {
private String plateNumber;
private T car;
public T getCar() {
return this.car;
}
public T setCar(T car) {
this.car = car;
}
public RegisteredCar (String plateNumber){
this.plateNumber=plateNumber;
}
public String getPlateNumber() {
return plateNumber;
}
}
With this, you will be able to pass into RegisteredCar an object of any type that's a subclass of Car.
As you can notice, I have removed the extends Car part of this class, as it doesn't need to be a subclass of car itself.
Is there a reason, in the real classes, that you couldn't simply add the new feature to the existing base class?
public abstract class Car
{
public abstract String getManufacturer() ;
protected String plate_number = null ;
public String getPlateNumber()
{ return this.plate_number ; }
public boolean isRegistered()
{ return ( this.plate_number != null ) ; }
}
I have a method in a class say
// super class
public class Car{
public void printMe(Car c){
if(c instanceof BMW){
Utility.printString("Bmw");
}else if(em instanceof VOLVO){
Utility.printString("Volvo");
}else if(em instanceof AUDI){
Utility.printString("Audi");
}else {
Utility.printString("Kia");
}
}
// sub classes
public class Bmw extends Car{
}
public class Volvo extends Car{
}
public class Audi extends Car{
}
public class Kia extends Car{
}
}
Now here i have a different class that loops through a list of Cars and print the correct statement according to the type of the Car
public class AccessCars{
ArrayLists<Car> carsList = listOfcars();
for(Car car: carsList){
car.PrintMe(car);
}
}
In the loop above i call the printMe(Car c) method on car en give car as an argument. Is is legal to do that? And if not, what is the best way of doing it?
thanks for your answer
a better way will be:
public abstract class Car {
public abstract void printMe();
}
public class Audi {
#Override
public void printMe() {
Utility.printString("Audi");
}
this is the OOP way to do it - using polymorphism
note that Car is implicit argument for printMe()
I would advise against polymorphism in this case -- every class prints out a string in the same way. The behavior is constant -- only the value printed varies. As such, the correct approach (IMO) is a variable that's printed out by printMe, and each derived class just initializes the variable appropriately.
It's legal, but not very good design. Perhaps a better approach is to define an abstract method Car.getModel() and implement it in each subclass to return the appropriate value. After all, you don't want to have to change the code for Car every time you add a new subclass.
Um, you can do that ... but I think you're missing the point of inheritance and overriding methods:
public class Car{
void printMe()
{
System.out.println("I'm a Car!");
}
}
public class Audi extends Car{
void printMe()
{
System.out.println("I'm an Audi!");
}
}
for(Car car: carsList){
car.PrintMe()
}
You get the overriden methods. Each car will print its name.
That being said, this is a silly example just to show how that works.
You'd really declare the Car class abstract and have printMe() be abstract, unless you had some reason to ever instantiate Car directly.
It's generally not acceptable to do this; since you already have "specialized" classes, why not put the printMe method in these classes? In case you want to enforce the subclasses have their own version of printMe, just make the printMe method in the super-class as abstract.
On a side note, another thing you might be interested would be a Visitor pattern:
In object-oriented programming and
software engineering, the visitor
design pattern is a way of separating
an algorithm from an object structure
it operates on. A practical result of
this separation is the ability to add
new operations to existing object
structures without modifying those
structures. It is one way to easily
follow the open/closed principle.
Definetly not OK, to do it.
I would define an abstract method called .Print() on the super class in such a way every subclass of Car must override it, and have your own way of Printing. Just like many samples above!
It is legal, however, not best of practice.
instanceof is a heavy operation on runtime environment and as such should be avoided if possible. This is not needed here, as every Car instance do the same thing - print itself. Consider this example:
public class Car {
// do some great stuff here...
public abstract String printMe();
}
public class Audi extends Car {
// do some great stuff here...
public String printMe() {
return "Audi rocks!";
}
}
// same for the other car models...
now iterate on the Car collection and run printMe for each.
Why do we need constructors and private members in the abstract class? It is not like we are ever going to create an instance of that class.
You will create instances, just instances of a derived class. Those derived classes will still need to call constructors, and can still call members of the abstract class - which may in turn use private members.
Here's an example (not a terribly useful one, but just to show the basic idea...)
public abstract class NamedObject
{
private final String name = name;
protected NamedObject(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
public class Computer extends NamedObject
{
private final int processorSpeed;
public Computer(String name, int processorSpeed)
{
super(name); // See, the constructor is useful
this.processorSpeed = processorSpeed;
}
public String toString()
{
return getName() + " (" + processorSpeed + ")";
}
}
I can't say I write abstract classes that often, generally preferring composition to inheritance, but when I do create them I certainly use constructors and private members.
Abstract classes provide a partial implementation of some interface. It's perfectly reasonable to consider that you might want to provide part of that implementation and disallow client code (concrete subclasses) from accessing the specifics - i.e. an extension of the principle of encapsulation.
Marking some members as private forces the inheriting class to call protected methods to access that partial implementation; providing a constructor allows for subclasses to initialise the parent's encapsulated state during their own construction.
Unlike an interface, an abstract class that defines data fields is in fact instantiated in the sense that these data fields are allocated. It is just that they are never instantiated on their own, they are instantiated as part of something bigger - the subclass. So when the subclass is built, the supertype is built as well, which is why you would need a constructor.
Depending on your hierarchy, your abstract class may have a meaning and state. For example, if your application is a school you may have the notion of a person (that has a name and an SSN), but you would have different subtypes for students and for faculty. Because both types of people share certain state structure (name and SSN) you would have both classes extend the Person class. But you would never simply instantiate a person directly.
In addition to Jon's answer, I'd like to mention that abstract classes still go well with composition, if you keep the subclass tree shallow. I.e. it is great for providing a common base class for a few closely related objects, but not for creating a gigantic tree of subclasses.
Why do you need private class? I think that you are confusing abstract classes with interfaces. Unlike interfaces, abstract classes can hold functionality. For example:
public class AbstractBase{
private int num;
public AbstractBase(int number){
this->num = number;
}
public int method(){
return ( this->num * this->templateMethod());
}
public abstract int templateMethod();
}
public class ConcreteDerived extends AbstractBase{
public ConcreteDerived(){
super(4);
}
public int templateMethod(){
return number; //number is the result of some calculation
}
}
In this example, you´ll never explicitly instantiate AbstractBase, but by declaring members and constructors, you can customize the functionality of your classes (this is called template method).
Assuming you're doing ad hoc code or prototyping, you do instantiate abstract classes (or maybe even interfaces) from time to time. They're called anonymous inner classes (one, two) and look like this:
// you have this...
public abstract class SomeClass {
public abstract String returnAString();
}
// ...and this...
public class OtherClass {
public void operate(SomeClass c) {
System.out.println(c.returnAString());
}
}
// ...so you do this:
OtherClass oc = new OtherClass();
// this is one of the reasons why you need to specify a constructor
oc.operate(new SomeClass() {
#Override
public String returnAString() {
return "I'm an anonymous inner class!";
}
});
This example is of course quite redundant but should expose the point. Some existing frameworks even rely on the heavy usage of this behaviour, namely Apache Wicket at least.