设计模式演化之观察者模式2——仿LiveData实现

本文探讨了在经典观察者模式的基础上如何优化以适应多个属性变化的观察需求。通过引入Observable接口和泛型,实现了不改变被观察对象源码的同时保持类型信息。此外,文章还展示了如何使用匿名内部类和Lambda表达式简化代码,提高代码可读性和可扩展性,以此模仿LiveData的设计思想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

设计模式演化之观察者模式1
中,我们实现了一个经典的观察者模式,下边继续对观察者模式进行优化,以便于能够在各种场景下更好的工作。

优化

1.我们在Subject中新增多个属性。然后一下Subject类的名字,使它更符合业务场景。现在我们要观察一个User类多个属性的变化。

public class User {
    private String name;
    private int age;
    private String address;
}

此时,你会发现按照前面观察者模式的写法麻烦就来了。之前,为了能让多个对象观察name属性的变化,我们专门定义个了一个Observer接口,并提供了它的实现类。如果新增的属性也按照这个模式去定义,那观察这个类的代价就太大了。显然经典模式的写法,不足以应对这种观察多个属性的情况。

你可能会想,能不能将这些被观察的属性也抽象出一个公共的接口Observable(注意不是Observer),让被观察的属性类实现这个接口来表示它是一个可观察对象呢?很遗憾,答案是否定的。

  • 首先,抽象之后会造成属性的类型丢失,这对观察它变化的类来说是不可行的。抽象之后所有的属性都变成了Observable类型了。
  • 要让被观察属性实现Observable接口,就需要去改这些属性类的源码,没有源码自然就改不了了。如第三库中的类。
  • 对于基本类型和String类型,我们无法让它们去实现这个抽象出来的接口。

此时,我们也可以得出观察多个属性时需要的基本要求

  • 被观察属性必须具备统一的通知观察者刷新的方法——onChange()。这样可以使得观察者只需要Observer接口就可以,观察该对象
  • 被观察的属性不能丢时类型,且通知观察者刷新时,必须在onChange()中传递准确的类型
  • 不得改动被观察属性类的源码

既然修改被观察属性的类源码行不通,那我们就考虑给它们包装一层,并在包装类里去调用onChange()方法,这样它们就可以具有统一的行为。然后为了保证属性类型不丢失,我们可以使用泛型来保存实际被观察的属性类型,当调用onChange()时,将实际类型传递出去。这里就要求onChange()方法也具备接收泛型的能力,因此还需要对Observer也做出相应的修改。代码如下

public class Observable<T> {
    
    private T value;
    private final List<Observer<T>> observers = new ArrayList<>();
    // 改一下方法名,使含义更突出。实际就是注册观察者的功能
    public void observe(Observer<T> observer) {
        observers.add(observer);
    }

    public void unregisterObserver(Observer<T> observer) {
        observers.remove(observer);
    }

    public void setValue(T value) {
        this.value = value;
        for (Observer<T> observer: observers) {
            observer.onChange(value);
        }
    }
}
public interface Observer<T> {
    void onChange(T t);
}

现在,我们可以重新定义User类中的属性了。

public class User {
    public Observable<String> name;
    public Observable<Integer> age;
    public Observable<String> address;
}

回想前面在观察多个对象时提出三条基本要求,这种做法已经满足要求了。

2.在上一步骤中,我们完成了对被观察属性的定义,下一步就是使用它们了。再定义UserManager,使它观察User中的各个数据变化,然后做出对应的操作。此时你会发现,麻烦还是有的。虽然我们统一了各个属性的观察方式,即实现Observer< T> 接口,但还是需要定义各个具体的实现类,而且UserManager与这些实现类的交互也非常麻烦。所以我们再改一种写法,将具体实现类在UserManager中以匿名内部类的形式实现。UserManager就可以在处理更多业务的同时,还具备了观察User属性的功能,代码如下:

public class UserManager  {
    
    User user = new User();

    private void initObserver() {
        user.name.observe(new Observer<String>() {
            @Override
            public void onChange(String s) {
                System.out.println(s);
            }
        });
        
        user.age.observe(new Observer<Integer>() {
            @Override
            public void onChange(Integer integer) {
                System.out.println(integer);
            }
        });
        
        user.address.observe(new Observer<String>() {
            @Override
            public void onChange(String s) {
                System.out.println(s);
            }
        });
    }
}

在Java 1.8 之后,我们还可以利用Lambda表达式来进一步优化上述代码。

public class UserManager  {

    User user = new User();

    private void initObserver() {
        user.name.observe(s -> {
            // do many things
            System.out.println(s);
        });
        user.age.observe(integer -> {
            // do many things
            System.out.println(integer);
        });
        user.address.observe(s -> {
            // do many things
            System.out.println(s);
        });
    }
}

代码量得到了极大的简化。不过这么写依然会存在一点小问题。我们这里对于变化的结果只是调用了System.out.println把它输出而已。真正的业务场景,这里显然会比较复杂,可能会有二三十行代码。当可观察变量增加时,这些变化后的处理逻辑会混合在一起,难以阅读,且会导致initObserver()方法的行数爆表。因此还需要做一点小小的改动。

public class UserManager  {

    User user = new User();

    private void initObserver() {
        user.name.observe(this::onNameChange);
        user.age.observe(this::onAgeChange);
        user.address.observe(this::onAddressChange);
    }

    private void onNameChange(String name) {
        // do many things
        System.out.println(name);
    }

    private void onAgeChange(int age) {
        // do many things
        System.out.println(age);
    }

    private void onAddressChange(String address) {
        // do many things
        System.out.println(address);
    }
}

虽然看上去多定义三个方法,但是这样把三者的逻辑解开了,而且避免了initObserve()中代码过多的问题。以后新增可观察对象时,也更加容易扩展。因此这时多写一些代码是完全值得的。

总结:最终,我们通过新增Observable< T> 和Observer< T> 两个文件。就可以很方便的在任何对象之间建立观察者关系。这也是RxJava与Android中LiveData对于观察者模式的应用,当然这里只是简单的模仿实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值