简体   繁体   中英

Inheritance or not

I am working on a component which is supposed to:

  1. receive data (collection of items) from some external calculation component. I expect about 100-1K of items on input on each request.

  2. validate data, calculate some attributes if missing

  3. 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?

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.

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();
    }
}

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
  • ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM