Вопрос реализации относительно базовых классов и производных классов - PullRequest
1 голос
/ 09 марта 2010

У меня вопрос о том, как лучше всего это реализовать. Я собираюсь описать мою текущую реализацию и то, как я, кажется, загнал себя в угол:

У меня есть абстрактный класс 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, я должен его разыграть (кажется, что это немного глупо).

У меня вопрос: как мне реализовать это лучше (чтобы мне не приходилось использовать), а также обеспечить безопасность типов (чтобы при использовании OrderQuantityPackageShipService пакет должен был иметь тип OrderQuantityPackage). Я думал об использовании Generics, но мне кажется, что то, что я пытаюсь сделать, немного усложняет (ShipRequest имеет кучу других атрибутов, и было странно обобщать его на основе типа пакета).

Спасибо.

Ответы [ 4 ]

1 голос
/ 09 марта 2010
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 класс, которому нужно или требуется количество, может сделать это, переопределив метод получения и установки свойства Количество.

Не должно быть выброшено исключение, поскольку количество не потребуется, оно не должно вызываться, поэтому не должно быть выброшено исключение. Кроме того, это свидетельствует о том, что ваша модель делает только то, что требуется, когда придет время.

В дополнение к этому OrderQuantityShipService не должен требовать свойства Weight в OrderQuantityPackage, и, как написано Vivin, в любом случае можно получить доступ к весу.

В противном случае, простое приведение в действие должно сделать это. Это не грязный способ использовать кастинг. Например, необходимо привести объект-отправитель в обработчике события к соответствующему типу элемента управления, который он хочет проверить на предмет имени, состояния или других значений свойств! Затем на событие передается самый общий класс, и его нужно разыграть ... И это, это не я, кто сказал, что я выбрал этот путь, это инженеры программного обеспечения! ...

РЕДАКТИРОВАТЬ Вивин, как преобразовать один тип данных в другой в JAVA, как в C / C ++ / C #?

CastedType variable = (CastedType)TypeCast; 
0 голосов
/ 09 марта 2010

Краткий ответ: инверсия зависимостей

У вас есть класс OrderQuantityPackageShipService, который требует определенных функций от объектов, которые он обрабатывает. Таким образом, OrderQuantityPackageShipService должен быть тем, который определяет эти требования. Обычно это делается с помощью интерфейса. Если это очень специфично для сервиса, создайте вложенный интерфейс. а именно:

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

если он может использоваться согласованным образом другими службами, определите его вне класса OrderQuantityPackageShipService.

Тогда определенные пакеты реализуют этот интерфейс ...

0 голосов
/ 09 марта 2010

Одна вещь, о которой я могу подумать, - зачем вам нужен доступ к атрибуту quantity в классе OrderQuantityPackageShipService? На мой взгляд, у вас есть геттер и сеттер для каждого атрибута класса Package. Эти геттеры и сеттеры действительно нужны? Наличие getters / setters для всех этих атрибутов не подходит для инкапсуляции.

Можете ли вы представить публичные методы в классе Package, которые работают на более высоком уровне и не раскрывают внутренние атрибуты? Разве это не поможет?

0 голосов
/ 09 марта 2010

Может быть, вам следует создать абстрактный сервис и расширить его для различных типов пакетов, которые будут обрабатываться. Вы можете сделать так, чтобы метод обработки был абстрактным, и каждый вид службы знал, что делать с соответствующим пакетом. Если вы не хотите смешивать типы пакетов, это может сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...