Вот единственное решение, которое я придумал, которое следует за присваиванием букве и все еще имеет некоторый смысл (хотя я думаю, что это не «хорошее» решение - см. Примечания ниже) ): ComputerOrder
и PartyTrayOrder
могут предлагать методы, которые только принимают специализированные типы Product
:
abstract class Product {}
class ComputerPart extends Product {}
class Peripheral extends Product { }
class Cheese extends Product {}
class Fruit extends Product {}
class Service extends Product {}
abstract class GenericOrder<T extends Product> {
protected final void addImpl(T t) {
}
}
class ComputerOrder extends GenericOrder<Product> {
void add(ComputerPart t) {
addImpl(t);
}
void add(Peripheral t) {
addImpl(t);
}
void add(Service t) {
addImpl(t);
}
}
class PartyTrayOrder extends GenericOrder<Product> {
void add(Cheese t) {
addImpl(t);
}
void add(Fruit t) {
addImpl(t);
}
void add(Service t) {
addImpl(t);
}
}
Таким образом, реализации заказа могут точно принимать правильные типы:
public class ProductExample {
public static void main(String[] args) {
ComputerOrder c = new ComputerOrder();
c.add(new ComputerPart());
c.add(new Peripheral());
//c.add(new Cheese()); // Not allowed
//c.add(new Fruit()); // Not allowed
c.add(new Service());
PartyTrayOrder p = new PartyTrayOrder();
//p.add(new ComputerPart()); // Not allowed
//p.add(new Peripheral()); // Not allowed
p.add(new Cheese());
p.add(new Fruit());
p.add(new Service());
}
}
Я предполагаю, что это намеченное решение, потому что назначение содержит широкий намек:
Реализуйте столько методов, сколько необходимо.
Так что, скорее всего, целью является , а не , чтобы реализовать один метод, магически ограниченный для нескольких классов. Вместо этого необходимо добавить один метод для каждой категории.
В сторону: я чувствую, что этот дизайн можно улучшить. Представьте, что вам нужно создать классы CarOrder
, FahsionOrder
и т. Д. Для новых типов заказов. Или представьте, что PartyTrayOrder
нужно будет расширить, чтобы также обрабатывать классы, такие как Meat
или Dip
или Salad
: в итоге вы получите десятки классов с десятками специализированных методов.
Этого можно избежать, введя специальный «тип продукта», который точно соответствует типам, которые приемлемы для определенного «типа заказа». Поэтому я думаю, что (Product
должен быть интерфейс для начала, и) должны быть интерфейсы, такие как ComputerProduct
и PartyTrayProduct
, как в
interface Product {}
interface ComputerProduct extends Product {}
class ComputerPart implements ComputerProduct {}
class Peripheral implements ComputerProduct {}
interface PartyTrayProduct extends Product {}
class Cheese implements PartyTrayProduct{}
class Fruit implements PartyTrayProduct{}
class Service implements Product {}
class DeliveryService implements PartyTrayProduct{}
class AssemblyService implements ComputerProduct {}
Таким образом, требуемые границы для конкретных ComputerOrder
и PartyTrayOrder
уже смоделированы с помощью иерархии классов. Преимущество: Вам больше не нужны классы ComputerOrder
и PartyTrayOrder
! Тогда GenericOrder
может быть неабстрактным, и для создания определенных типов заказов вы просто правильно использовать привязку общего типа.
Вот полный пример, где я только что добавил Salad
как новый PartyTrayProduct
и CarPart
как новый тип продукта, без необходимости расширять или изменять какие-либо "классы инфраструктуры" :
interface Product {}
interface ComputerProduct extends Product {}
class ComputerPart implements ComputerProduct {}
class Peripheral implements ComputerProduct {}
interface PartyTrayProduct extends Product {}
class Cheese implements PartyTrayProduct{}
class Fruit implements PartyTrayProduct{}
class Service implements Product {}
class DeliveryService implements PartyTrayProduct{}
class AssemblyService implements ComputerProduct {}
class Salad implements PartyTrayProduct{} // A new PartyTrayProduct
// Entirely new product type:
interface CarProduct extends Product {}
class CarPart implements CarProduct {}
class CarInterior implements CarProduct {}
class GenericOrder<T extends Product> {
public void add(T t) { }
}
public class ProductExample2 {
public static void main(String[] args) {
GenericOrder<ComputerProduct> c = new GenericOrder<ComputerProduct>();
c.add(new ComputerPart());
c.add(new Peripheral());
//c.add(new Cheese()); // Not allowed
//c.add(new Fruit()); // Not allowed
c.add(new AssemblyService());
GenericOrder<PartyTrayProduct> p = new GenericOrder<PartyTrayProduct>();
//p.add(new ComputerPart()); // Not allowed
//p.add(new Peripheral()); // Not allowed
p.add(new Cheese());
p.add(new Fruit());
p.add(new Salad()); // Just add it...
p.add(new DeliveryService());
// Easy to extend:
GenericOrder<CarProduct> e = new GenericOrder<CarProduct>();
e.add(new CarPart());
e.add(new CarInterior());
}
}