Hello friends,

I have a Customer class (Parent class) and Member class (child class which extends Customer class).

the coding is like this

public class Customer
{
   String name;
}

public class Member extends Customer
{
   int memberID;
}

public class Tranasaction
{
   public void printTransaction(Customer customer)
   {
      if(customer.memberID exists)
      {
         give discount;
      }
   }
}

//another thought ----

public class Tranasaction
{
   public void printTransaction(Member customer)
   {
      if(customer.memberID exists)
      {
         give discount;
      }
   }
}

when i use first way, compiler is throwing error as usual Customer object is not aware of Member class details.
When i use second way, Compiler is fine but during run time when i pass Customer object as an argument against Member type, Its throwing error.

So how do i handle same printTransaction for both customers

You can test to see if the Customer object is actually a Member, and then cast it to the right class

public void printTransaction(Customer customer) {
 
  if (! customer instanceof Member) return;

  Member m = (Member) customer;
  if(m.memberID exists) {
    // give discount;
  }
}

Edited 5 Years Ago by JamesCherrill: n/a

@Nitin: What happens if you need to perform this 'discounting' check multiple times? What if the requirement changes to allows for only fixed set of 'memberIds' to avail the discount?

IMO, you should ask this question from to the entity in consideration rather than querying/deducting it yourself. One solution would be to have either a method in the Customer class or have a interface which is implemented by both Customer and Member which has the method isEligibleForDiscount() . Then you can have code which does:

public class Transaction {

  public void giveDiscount(final Customer c) {
    if(c.isEligibleForDiscount()) {
      // give discount
    } else {
      // no discount
    }
  }

  public void printReceipt(final Customer c) {
    if(c.isEligibleForDiscount()) {
      // print discounted receipt
    } else {
      // print usual receipt
    }
  }

}

OR

public class Transaction {
  // here Discountable is an interface implemented by both
  // Customer and Member so they are really not required
  // to be part of the same type hierarchy.
  public void giveDiscount(final Discountable c) {
    if(c.isEligibleForDiscount()) {
      // give discount
    } else {
      // no discount
    }
  }

  public void printReceipt(final Discountable c) {
    if(c.isEligibleForDiscount()) {
      // print discounted receipt
    } else {
      // print usual receipt
    }
  }

}

With the change in requirements, there might be other ways of doing the same but ensure that none of those approaches which you follow end up probing too deep in the Customer object without proper abstractions.

I've always subscribed to the principle that it's a bad idea to code stuff into a superclass when it's only needed in a subclass - eg putting "null" methods in the superclass when they only apply in the subclass.
Given that, in general I would prefer to use the interface approach and implement the interface only in the subclasses where it's appropriate

interface Discountable { ...
class Customer {
class Member implements Discountable {...

public void giveDiscount(Customer customer) {
  if (customer instanceof Discountable) {
    Discountable d = (Discountable) customer;
    // give discount for Customer d;
  }
}

For some reason I've always shied away from instanceof checks in my code which probably implies a broken type hierarchy.

Regarding the "coding stuff in super-class"; I don't think its wrong to ask a Customer whether he/she is actually eligible for a discount since a Customer availing for a discount is not unheard of. Plus it really isn't NULL but returning a right answer in this case. We ask the question: Is a cookie cutter Customer eligible for a discount? No, cool, then return false . Is our special Member class which *ISA* Customer eligible for discount? Yes, return true .

If the situation at hand can be adjusted so that the subclass-superclass relation can be avoided (the chances of which are thin if this is a homework), we can make the Discountable interface richer such that giveDiscount() method only accepts a Discountable and can complete its entire functionality by using the methods exposed by the Discountable interface ( getDiscountRate() etc).

Of course, IMHO and YMMV. :-)

In general I agree with you about instanceof checks - especially where its checking for a class rather than an interface. Unlike some pundits I don't think its always bad.
Eg SUV extends PetrolRoadVehicle extends RoadVehicle extends Transportation. PetrolRoadVehicle and its many subclasses but none of its superclasses have a public getMilesPerGallon() method. That's a case where I think the instanceof interface pattern is pretty much the only way to go. I certainly wouldn't put a method in Transportation to handle a situation that only applies to PetrolRoadVehicls.
IMHO and YMMV ditto

I guess we are both agreeing on the same thing; using interface instead of adding a method to super-class. My point being you can use an interface for it and still get away without doing the `instanceof` checks.

Edited 5 Years Ago by ~s.o.s~: n/a

This article has been dead for over six months. Start a new discussion instead.