我已经尝试寻找合适的解决方案,但很难找到它。
这是一个非常简单的问题 - 当我们想要在该类的实例中有很多时确定一个类类型时,是否存在使用INSTACEOF的正确,有效的替代方法?
例如:
我们有一个父Product
类
public abstract class Product {
public abstract String preview();
}
其中有3个子类(乙烯基,书籍和视频)
public class Vinyl extends Product {
@Override
public String preview() {
return "Playing a vinyl";
}
}
public class Book extends Product {
@Override
public String preview() {
return "Reading a book";
}
}
@Override
public String preview() {
return "Playing a video";
}
现在,我想根据每种产品类型检查它的预览方法返回值 - 当我们有 3 子类时,它在编写时非常清晰整洁: / p>
public class TestProduct {
List<Product> productList = new ArrayList<>();
public void preview(Product product) {
for (Product currentProduct : productList) {
String preview = currentProduct.preview();
if (product instanceof Book) {
Assert.assertEquals(preview, "Reading a book");
} else if (product instanceof Vinyl) {
Assert.assertEquals(preview, "Playing vinyl");
} else {
Assert.assertEquals(preview, "Playing video");
}
}
}
}
但是,如果我们没有3个产品,但是100个或更多?,该怎么办?
我写这个INSTACEOF
语句的次数是100次没有任何意义。
有没有适当的,可扩展的方式?
答案 0 :(得分:3)
这是使用interface
:
public interface class Product {
public void doSomething();
}
然后每个子类都必须实现自己的doSomething()
public class Vinyl implements Product {
public void doSomething(){
System.out.println("Vinyl product");
}
}
public class Book implements Product {
public void doSomething(){
System.out.println("Book product");
}
}
public class Video implements Product {
public void doSomething(){
System.out.println("Video product");
}
}
然后
Product product = new Vinyl();
product.doSomething();
// prints on the console --> "Vinyl product"
同样适用于实现接口产品的其他类。
抽象类无法实例化,在您的情况下没有帮助,这就是我使用接口的原因。
附注:通常当您需要使用instanceof
时,您可能使用了错误的设计。
答案 1 :(得分:2)
为什么不让你做的工作成为子类本身的一部分呢?
public abstract class Product {
abstract void doSomething();
}
然后,执行循环的代码不需要知道它具有什么类型的产品。它可以让产品决定做什么。
for (Product product : products) {
product.doSomething();
}
如果需要,doSomething()
方法可以有参数和返回类型。
您还可以将访问者模式用于同一主题的变体,以便您在实际的Product
实现类之外指定实现。
答案 2 :(得分:1)
使用多态或访客模式并不总是切实可行或可能,例如当您无法更改子类时,或者您希望基于特定子类型doSomething()
的许多不同情况时,例如当你有许多不同的装饰器时 - 你不希望子类本身的逻辑。在这种情况下,您可以使用外部处理程序,例如:
class Handler<T> {
private Map<Class<? extends T>, Consumer<? super T>> handlers = new HashMap<>();
Handler<T> register(Class<? extends T> subtype, Consumer<? super T> action) {
handlers.put(subtype, action);
return this;
}
void handle(T instance) {
Optional.ofNullable(instance)
.map(Object::getClass)
.map(this.handlers::get)
.orElseThrow(() -> new IllegalStateException("Unknown subtype!"))
.accept(instance);
}
}
用法:
Handler<Product> productHandler = new Handler<Product>()
.register(Vinil.class, vinil -> gramophone.play(vinil.sideB()))
.register(Book.class, book -> library.put(book.isbn(), book))
.register(Video.class, video -> { /* no-op */ });
products.stream()
.forEach(productHandler::handle);
答案 3 :(得分:1)
一种可能的解决方案是享受多态性
public static void check(Object o) {
List<? extends Products> list = Arrays.asList(new A(), new B(), new C());
if (o instanceof Products) {
Products p = (Products) o;
p.doSomething();
}
}
,界面是
public interface Products {
public void doSomething();
}