【问题标题】:Looping through a list of different objects that share the same super class and get one specific type循环遍历共享相同超类的不同对象列表并获取一种特定类型
【发布时间】:2018-08-11 10:20:02
【问题描述】:

我正在使用 Java 练习观察者设计模式。
我有两种类型的客户。
一个对价格感兴趣,另一个对可用性感兴趣。
我正在尝试重构以下代码:

public void setAvailable(boolean available) {

    this.available = available;
    if (this.available == true)
        for (Iobserver o : allObservers) {
            if (o instanceof CustomerAvailabilityObserver)
                notify(o);
        }
}

有人告诉我,每当我使用instanceof 时,我的代码中都会散发出一种可以修复的难闻气味。
关于如何重写 for 循环的任何想法?顺便说一句,观察者存储在ArrayList

【问题讨论】:

  • 你可以先存储两个列表
  • @user7:两个列表并不代表一种干净的方法,因为它们的维护/同步更复杂。
  • @user7 是的,这可能是一个很好的解决方案。但安托特现在让我思考复杂性。

标签: java refactoring observable observer-pattern observers


【解决方案1】:

您可以在客户类中编写决定他们兴趣的函数:

boolean notifyOnAvailabilityChange();
boolean notifyOnPriceChange();

所以你可以把循环写成类似

allObservers.filter(o -> o.notifyOnAvailabilityChange()).forEach(this::notify);

【讨论】:

  • 我想我可以摆脱不同类型的客户并在 Customer 类中实现所有不同的通知因素?
  • 我不能说。我不知道你为什么一开始就有不同的实现。
  • 我发送了我的新实现作为答案,如果可以的话,请看一下 :)
【解决方案2】:

这是 Turo@'s answer 的延伸。

基本思想是每个观察者都会告诉他们感兴趣的事件(状态变化)。然后,当事件发生时(某些状态,如价格或可用性变化),您只通知那些对该事件感兴趣的人。

我将每个应通知的状态更改(如价格、可用性)称为Factor。观察者会告诉他们感兴趣的因素列表。

enum Factors {
   PRICE,
   AVAILABILITY
   //and so on
}

Observer 接口会有一个方法让 Observer 返回感兴趣的 Factors 列表

interface IObserver {
    List<Factors> interestedFactors();
    //other existing methods
}

观察者示例:

class Observer1 implements IObserver {
    @Override
    public List<Factors> interestedFactors() {
        return ImmutableList.of(Factors.PRICE);
    }
}
class Observer2 implements IObserver {
    @Override
    public List<Factors> interestedFactors() {
        //Some might be interested in multiple states
        return ImmutableList.of(Factors.PRICE, Factors.AVAILABILITY);
    }
}

一旦状态发生变化,您可以过滤对该状态感兴趣的观察者并通知他们。

allObservers.stream()
            .filter(observer -> observer.interestedFactors().contains(Factors.<whatever_the_cuurent_state_change_is>))
            .forEach(observer -> notify(observer));

优点:

  1. Subject 未与任何其他观察者耦合。
  2. 更容易添加新的状态类型(价格、可用性除外)

缺点:

  1. 如果引入了新状态并且必须通知所有现有观察者,则必须将其添加到所有现有观察者的interestedFactors 列表中。

【讨论】:

  • ImmutableList.of 对我不起作用。我尝试使用 Collections.unmodifiableList(list);但我收到此错误:错误消息:Collections 类型中的方法 sort(List) 不适用于参数 ...
  • @MousKamel 来自 Google Guava。我展示它只是为了演示返回一个因素列表。你可以使用任何你方便的东西。简单的 ArrayList 就可以了。
  • 我没有什么不同,它现在看起来不错并且可以工作,但我必须修复 OpenClose 问题
【解决方案3】:

感谢 Turo 和 User7。这就是我所做的。我不知道这是否是最好的解决方案,因为我不仅必须订阅观察者,而且客户也必须选择他们的兴趣。它不像订阅价格或可用性那样直接。

public enum Factors {
    AVAILABILITY, PRICE
}

然后在我的客户类中,我们在观察哈希图中设置兴趣。

public class Customer implements Iobserver {
    String name;
    String email;

    private EnumMap<Factors, Boolean> observations = new EnumMap<Factors, Boolean>(Factors.class);

    public Customer(String name, String email) {
        this.name = name;
        this.email = email;

        for (Factors factor : Factors.values()) {
            observations.put(factor, false);
        }
    }

    public void setObsevation(Factors factor, Boolean isInterested) {
        observations.put(factor, isInterested);
    }

    public boolean getObservation(Factors factor) {
        return observations.get(factor);
    }

    public void update(Product p, Factors factor) {

        System.out.println("Dear customer " + this.name + ", the " + factor.toString().toLowerCase() + " of "+ p.getProduct() + " has changed! ");

    }
}

在我的 Product 类中,观察者列表所在的位置。我添加了这个。

public void setPrix(float prix) {
        if (prix != this.prix) {
            this.prix = prix;

            for (Iobserver o : allObservers) {
                if (o.getObservation(Factors.PRICE)) {
                    notify(o,Factors.PRICE);
                }
            }
        }
    }

    public void setAvailable(boolean available) {

        this.available = available;
        if (this.available == true)
            for (Iobserver o : allObservers) {
                if (o.getObservation(Factors.AVAILABILITY))
                    notify(o,Factors.AVAILABILITY);
            }
    }

    public void notify(Iobserver o, Factors factor) {
        o.update(this,factor);
    }

我可以在每个因素通知之后添加一个策略。

【讨论】:

  • 使用这个因素我不会使用这个 ObservationsMap 但每次都调用 o.update(this, factor) 并让客户决定是否立即返回。顺便说一句,我会写if (this.available)
猜你喜欢
  • 2013-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多