Check if Calling Object is Instance of Child Class
I have 2 classes. Let's call them class A and class B. 开发者_运维百科 Class A contains a method that executes some action. Class B overrides this method with its own version, but does make a super
call to that method in class A to perform an action. Right now, this is working fine. However, there are some actions in class A that should only be executed if the object is only an instance of class A. Put another way, some actions in the Class A method should not happen if the object is an instance of a child of Class A.
Currently, I'm using instanceof
to check for each child, but I need to specify each child class, so if a new child is added at a later date, this method needs to be updated. What I would like is a dynamic way of determining if the object is a child class.
Are there any good alternatives, or is instanceof
the way to go?
public class A{
public void someMethod(){
// Only perform these actions if it is not a child class. This is what
// I am looking for a better solution for
if(!(this instanceof B)){
// Some action...
}
// Actions to execute for every call
}
}
public class B extends A{
@Override
public void someMethod(){
super.someMethod();
// More actions
}
}
Just as an explanation of the design, I am using it to generate XML. In the program, I have a List<A>
to store the data. When it is time to output the XML, I loop through the list and call generateXML
(the someMethod
takes its places in my example).
When an object of class A is created, it needs to have its data within <A></A>
tags. When an object of class B is created, it needs to have its data within <B></B>
tags. But all the properties of A
must also be inside the <B></B>
tags, so as of right now it calls the same generateXML
method used when an object is only of of Class A
But as some others have pointed out, calling that same method isn't the way to go. Class B
should be calling a protected method in class A
that only generates the necessary information.
Create protected methods that do the class-specific things, and call them from someMethod(). Class A will provide its implementation, and if a subclass needs to effectively remove that code, then it can override the protected method with an empty implementation.
Don't fight polymorphism; use it to your advantage.
Example:
public class A {
protected void someOtherMethod() {
// Do stuff specific to A here.
}
public void someMethod() {
// Do some stuff
someOtherMethod();
// Do some more stuff
}
}
public class B extends A {
@Override
protected void someOtherMethod() {
// Empty implementation; B doesn't need to do this.
// Or do stuff specific to B...
}
}
Well now that's a horrible design and should be solved in a different way (eg make the part that is called from the subclass a own protected method), but alas if you really need it you can check for
this.getClass() == A.class to see if the class is really identical.
I see instanceof
as an opportunity to use polymorphism.
Keep behavior in someMethod
common to all types of A
. Subclass A
to implement behavior you're currently checking for with the instanecof
.
public class A{
public void someMethod(){
// Get rid of the special section and put it in it's own class
// Keep only agnostic behavior common to all types of A
// Actions to execute for every call
}
}
public class B extends A{
@Override
public void someMethod(){
super.someMethod();
// More actions
}
}
public class C extends A{
@Override
public void someMethod(){
super.someMethod();
// Actions that were originally in the if(instanceof) check
}
}
This may be the same as what cdhowie was trying to say. (No offense: I thought you were a little unclear.)
Don't use instanceof. Instead, create methods that return flags or other appropriate values for the given type.
Your example doesn't give any details of what you're trying to do, so I'll just invent something.
!!! Wrong way !!!
public class Car
{
public void goUphill()
{
// XYZ has automatic transmission -- don't need to downshift
if (!(this instanceof XYZ())
{
downshift();
}
pressGas();
}
}
public class ModelXYZCar extends Car
{
public void goUphill()
{
tellWifeToGetOutAndPush();
super.goUphill();
}
}
Better way:
public class Car
{
public boolean isManualTransmission()
{
// default
return true;
}
public void goUphill()
{
if (isManualTransmission())
{
downshift();
}
pressGas();
}
}
public class ModelXYZCar extends Car
{
public boolean isManualTransmission()
{
return false;
}
public void goUphill()
{
tellWifeToGetOutAndPush();
super.goUphill();
}
}
This way, the super class doesn't have to know what the subclasses need. Each subclass defines its own behavior. In this case, each subclass defines an isManualTransmission function and returns true or false as appropriate.
Better still is to avoid the need for flags and put the appropriate behavior in each class:
abstract public class Car
{
abstract public void downshift();
public void goUphill()
{
downshift();
pressGas();
}
}
public class AutomaticTransmissionCar extends Car
{
public void downshift()
{
// Automatic transmission -- no need to do anything
}
}
public class ManualTransmissionCar extends Car
{
public void downshift()
{
... whatever ...
}
}
public class ModelXYZCar extends ManualTransmissionCar
{
public void goUphill()
{
tellWifeToGetOutAndPush();
super.goUphill();
}
}
Why not:
public class A{
public void someMethod(){
// Only perform these actions if it is not a child class. This is what
// I am looking for a better solution for
if(this.getClass().equals(A.class))
// Some action...
}
// Actions to execute for every call
}
}
And
public class B extends A{
@Override
public void someMethod(){
super.someMethod();
// More actions
}
}
Expression A.class.equals(this.getClass())
returns true only if this is really the instance of class A. If it is child instance the result will be false.
BUT: if you have to do this check your design. It sounds very not object oriented style. I can give you an alternative. Separate your base class A onto 2: the really base class A0 and its child A1. Your class B will be the brother of A1 and will extend directly from A0.
In this case you can put the common code into class A0 and all specific code (that in your version must be executed only if the class is exactly A and not its subclass) to A1.
"call super" is an anti-pattern. Instead of expecting the subclass to invoke superclass functionality, turn it the other way around. Now the superclass has complete control of what's called both before and after the "common" stuff.
public class A {
public void someMethod() {
beforeCommonStuff();
// Actions to execute for every call
afterCommonStuff();
}
protected void beforeCommonStuff() {
// Actions to execute only for class A
}
protected void afterCommonStuff() {}
}
public class B extends A {
@Override
protected void afterCommonStuff(){
// More actions
}
}
I could be mistaken, but your case seems like the ideal scenario to "favour composition over inheritance" and "encapsulate what varies". One general course of action in a situation like yours is to:
- Not have your subclasses extend from the superclass
- Isolate the section of code that should only belong to A in a private method.
Create an instance of A in B, C, etc and call A.someMethod().
public class A { public void someMethod(){} private void someOtherMethod(){ // move behavior specific to A in here. } } public class B { // no extends public void someMethod() { new A().someMethod(); } }
Again, I could be wrong and this might not apply to your case.
精彩评论