有关基类和派生类的实现问题

时间:2010-03-09 17:16:36

标签: java design-patterns oop inheritance polymorphism

我对实现此问题的最佳方法有疑问。我将描述我目前的实施情况,以及我如何将自己描绘成一个角落:

我有一个名为Package的抽象类:

public abstract class Package {
    protected String description;
    protected String packagingCode;
    protected Dimension dimensions;
    protected Weight weight;

    protected Package() {
        this.description = null;
        this.packagingCode = null;
        this.dimensions = null;
        this.weight = null;
    }

    protected Package(String description, String packagingCode, Dimension dimensions, Weight weight) throws ShippingException {
        this.description = description;
        this.packagingCode = packagingCode;
        this.dimensions = dimensions;
        this.weight = weight;

        String exceptionMessage = "";

        if(!meetsWeightRequirements()) {
            exceptionMessage = "This package's weight exceeds limits. ";
        }

        if(!meetsDimensionalRequirements()) {
            exceptionMessage += "This package's dimensions exceed limits.";
        }

        if(!StringUtils.isEmpty(exceptionMessage)) {
            throw new ShippingException(exceptionMessage);
        }
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getPackagingCode() {
        return packagingCode;
    }

    public void setPackagingCode(String packagingCode) {
        this.packagingCode = packagingCode;
    }

    public Dimension getPackageDimensions() {
        return dimensions;
    }

    public void setPackageDimensions(Dimension dimensions) throws ShippingException {
        this.dimensions = dimensions;

        if(!meetsDimensionalRequirements()) {
            this.dimensions = null;
            throw new ShippingException("This package's dimensions exceed limits.");
        }
    }

    public Weight getPackageWeight() {
        return weight;
    }

    public void setPackageWeight(Weight weight) throws ShippingException {
        this.weight = weight;

        if(!meetsWeightRequirements()) {
            this.weight = null;
            throw new ShippingException("This package's weight exceeds limits.");
        }
    }


    public abstract boolean meetsWeightRequirements();

    public abstract boolean meetsDimensionalRequirements();
}

然后我有类扩展这个抽象类的类:

public class WeightBasedPackage extends Package {

    public boolean meetsWeightRequirements() {
        Weight weight = this.getPackageWeight();
        boolean meetsRequirements = false;

        if(weight != null) {
            meetsRequirements = (weight.getWeight() > 0);
        }

        return meetsRequirements;
    }

    public boolean meetsDimensionalRequirements() {
        return true;
    }
}

我有另一个对象(ShipRequest)维护一个包列表(List<Package>)。我还有一个服务(例如WeightBasedPackageShipService),它使用这个对象并可以访问这个包列表。这种实现工作正常,因为服务并不真正关心它是什么类型的包。包之间的唯一区别是它们实现抽象方法的方式。

现在问题就出现了。我创建了一个新类:

public class OrderQuantityPackage extends Package {

    int quantity;

    public OrderQuantityPackage() {
        super();
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public int getQuantity() {
        return this.quantity;
    }

    public boolean meetsWeightRequirements() {
        return true;
    }

    public boolean meetsDimensionalRequirements() {
        return true;
    }
}

其中包含quantity字段。我需要在服务中访问此字段(OrderQuantityPackageShipService)。但是,由于它是Package类型,我必须施放它(它看起来有点像kludgey)。

我的问题是,我如何以更好的方式实现这一点(所以我不需要强制转换)并确保类型安全(所以如果你使用OrderQuantityPackageShipService,那么包必须是输入OrderQuantityPackage)。我想过使用Generics,但是对于我想要做的事情来说似乎有点尴尬(ShipRequest有一堆其他属性,根据包的类型对它进行泛化似乎很奇怪。)

感谢。

4 个答案:

答案 0 :(得分:1)

public abstract class Package {
    protected String description;  // These shouldn't be private fields instead of protected?
    protected String packagingCode; // Nah, I don't think so, otherwise how could I store a value into the Quantity field? =P 
    protected Dimension dimensions;  
    protected Weight weight;  
    protected int quantity;

    // Constructors, getters and setters...

    public virtual int getQuantity {
        throw new NotImplementedException();
    }

    public virtual int setQuantity(int quantity) {
        throw new NotImplementedException();
    }
}

public final class OrderQuantityPackage extends Package {
    public override int getQuantity {
        return super.quantity;
    }

    public override void setQuantity(int quantity) {
        super.quantity = quantity;
    }
}

我不完全确定语法,也没有关于NotImplementedException,但我希望你明白这个想法。因此,任何需要或需要数量的Package派生类都可以通过覆盖Quantity属性的getter和setter来实现。

不应该抛出任何异常,因为不需要数量,不应该调用它,因此不应抛出任何异常。此外,它证明了您的模型仅在时机成熟时才能满足要求。

除此之外,OrderQuantityShipService不应要求OrderQuantityPackage中的Weight属性,并且如Vivin所写,无论如何都可以访问权重。

否则,您服务中的简单演员应该这样做。使用铸造并不是一种肮脏的方式。例如,必须将事件处理程序中的sender对象强制转换为他希望检查名称,状态或其他属性值的正确控件类型!最普通的课程然后被传递给活动,一个人必须投...然后,这不是我说选择这种方式的人,这些是软件工程师!...

编辑 Vivin,在JAVA中如何从数据类型转换为另一个,是否与C / C ++ / C#中一样?

CastedType variable = (CastedType)TypeCast; 

答案 1 :(得分:0)

也许你应该创建一个抽象服务并扩展它以便处理不同类型的包。您可以将处理方法设计为抽象,并让各种服务知道如何处理相应的包。如果您不想混合使用各种类型的包,那么这可能会有效。

答案 2 :(得分:0)

简答:依赖性倒置

您有一个OrderQuantityPackageShipService类,需要来自其处理的对象的某些功能。因此,OrderQuantityPackageShipService应该是指定这些要求的那个。通常,这是通过接口完成的。如果它非常特定于服务,请创建嵌套的接口。即:

class OrderQuantityPackageShipService {
    //...
    interface QuantityPackage {
        int getQuantity();
        // ...
    }
}

如果其他服务可以以一致的方式使用 ,请在OrderQuantityPackageShipService类之外定义它。

然后让某些包实现该接口......

答案 3 :(得分:0)

我能想到的一件事是你为什么需要访问班级quantity中的OrderQuantityPackageShipService属性?在我看来,你有一个getter和setter用于类Package的每个属性。这些吸气剂和制定者真的需要吗?拥有所有这些属性的getter / setter并不适合封装。

您是否可以考虑在Package类中提供更高级别的公共方法并且不公开内部属性?这不会有帮助吗?