Hedley

Stay Hungry, Stay Foolish.

不负责瞎说说 Patterns 与 Frameworks

引出

Effective Java, Item 16 中说 Wrapper classes are not suited for use in callback frameworks,想不明白,一顿 Google 依旧看个似懂非懂。我想把这些凌乱的线索都整理出来,抽抽剪剪排列组合一下,也许就看的透彻点了呢。

关于 Wrapper class 的引出问题,个人认为比较炫酷的解答

Because a wrapped object doesn’t know of its wrapper, it passes a reference to itself(this) and callbacks elude the wrapper. This is known as the SELF problem [Lieberman86]. This leads to subtle bugs, like the wrapper missing the event. Or the wrapper and wrapped object both registering for the same events - leading to duplicate processing and potential concurrency issues as well. If you don’t know (don’t have the source code) where callbacks are registered, it may be impossible to work around this problem.

Panttern? Framework?

引出中的 Wrapper classDecorator pattern 的引出概念,callback frameworks 是一种 framework。从翻译上看,pattern 译为 模式framework 译为 框架。那么这个 patternframework 有毛的区别呢?

Introduction to Patterns and FrameworksDesign patterns vs Frameworks 对这个问题都有比较系统的分析,各位看官可以细细品看一下。一言以蔽之,pattern 是解决某个具体问题的方案,framework 是一套系统架构可重用的组件(通常包括若干个 pattern),他们经常共同为软件系统的可重用性、可扩展性提供支持。

Patterns support reuse of software architecture and design: Patterns capture the static and dynamic structures and collaborations of successful solutions to problems that arise when building applications in a particular domain.
Frameworks support reuse of detailed design and code: A framework is an integrated set of components that collaborate to provide a reusable architecture for a family of related applications.

Framework

Inversion of Control

打个比方:Frameworks 就是挖好了一堆坑,让你往里面填萝卜,填肥料。不同的肥料怎么找对应的萝卜 Frameworks 来接手,这个过程就是控制反转Inversion of Control)啦。

Don’t call us, we’ll call you.

Hollywood principle

Dependency injection

从代码上看,IoC 的实现主要包括依赖注入Dependency injection),以及其他的一些 Patterns。所以准确的来说,Dependency injection 是实现 IoC 的一种途径,但是现在很多的技术鸡汤文都把它们划上了等于号,这里了解一下概念即可,无伤大雅。

SoFrameworks 的基础是 IoC,而 IoC 的基础又是 Dependency injection。不要被这个高大上的名词唬到,其实它(主要)就是 set 方法而已。

Callback frameworks

如果说 IoC 的精髓一句话概括为:Don’t call us, we’ll call you.

那么回调callback)的一句话概括就是:If you call me, i will call back.1

callback frameworks 其实并不是一种具体的 framework,而是代表一类 framework。比如大多数的 GUI frameworks,比如 SAX (Streaming XML) XML parsers

Demo code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Context implements A.Callback {

    private A a;

    public void begin() {
        System.out.println("begin ...");
    }

    public void end() {
        System.out.println("end ...");
    }

    public Context() {
        this.a = new A(this);
    }

    public void doSomething() {
        this.a.doIt();
    }

    public static void main(String args[]) {
        new Context().doSomething();
    }
}

public class A {

    private final Callback callback;

    public static interface Callback {
        public void begin();
        public void end();
    }
    public A(Callback callback) {
        this.callback = callback;
    }
    public void doIt() {
        callback.begin();
        System.out.println("do something ...");
        callback.end();
    }
}

Spring

如果要找一种具体的 framework,最典型的当然非 Spring 莫属。

网上介绍的文章一箩筐,比如这两篇,戳这里戳这里。可以简单的看一下,主要是加深对 Dependency injection 的理解。

Pattern

Decorator pattern

Favor composition over inheritance. Inheritance propagates any flaws in the superclass’s API, while composition lets you design a new API that hides these flaws.

装饰者模式是继承可实例化的类的替代解决方案,Effective Java, Item 16 一节的主题正是 Favor composition over inheritance。B 继承可实例化的类 A 有很多问题,比如

  • B 依赖于 A 的实现细节,如果 A 的后续版本中更新了实现细节,可能会破坏 B
  • A 在后续版本中可能会加入新的方法,不满足 B 的 check
  • A 的后续版本中加入了新方法 m,不巧 B 提前声明了 m
  • B 不可能实现一个满意的 equals 方法(Effective Java, Item 8

Demo code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Wrapper class - uses composition in place of inheritance
public class InstrumentedSet<E> extends ForwardingSet<E> {
    private int addCount = 0;

    public InstrumentedSet(Set<E> s) {
        super(s);
    }

    @Override
    public boolean add(E e) {
        addCount++;
        return super.add(e);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return super.addAll(c);
    }

    public int getAddCount() {
        return addCount;
    }
}

// Reusable forwarding class
public class ForwardingSet<E> implements Set<E> {
    private final Set<E> s;
    public ForwardingSet(Set<E> s)         { this.s = s;                }
    public void clear()                 { s.clear();               }
    public boolean contains(Object o)   { return s.contains(o);    }
    public boolean isEmpty()            { return s.isEmpty();      }
    public int size()                   { return s.size();         }
    public Iterator<E> iterator()       { return s.iterator();     }
    public boolean add(E e)             { return s.add(e);         }
    public boolean remove(Object o)     { return s.remove(o);      }
    public boolean containsAll(Collection<?> c)
                                        { return s.containsAll(c); }
    public boolean addAll(Collection<? extends E> c)
                                        { return s.addAll(c);      }
    public boolean removeAll(Collection<?> c)
                                        { return s.removeAll(c);   }
    public boolean retainAll(Collection<?> c)
                                        { return s.retainAll(c);   }
    public Object[] toArray()           { return s.toArray();      }
    public <T> T[] toArray(T[] a)       { return s.toArray(a);     }
    @Override public boolean equals(Object o)
                                        { return s.equals(o);      }
    @Override public int hashCode()     { return s.hashCode();     }
    @Override public String toString()  { return s.toString();     }
}

再谈引出

Wrapper classes are not suited for use in callback frameworks,在了解了相关的各种基本概念后,现在可以给出示例代码了。结合之前介绍的 callback framework demo code 进行说明,给 Context 一个 Wrapper class,观察效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ContextB implements Callback {

    Callback real;

    public ContextB(Callback real) {
        this.real = real;
    }

    @Override
    public void begin() {
        System.out.println("B begin ...");
        real.begin();
    }

    @Override
    public void end() {
        System.out.println("B end ...");
        real.end();
    }

    public void ex() {
        System.out.println("B ex ...");
        real.ex();
    }

    public static void main(String args[]) {
        Callback real = new Context();
        new ContextB(real).ex();
    }
}

观察输出,有豁然开朗的感觉吗?有请点赞~

1
2
3
4
B ex ...
begin ...
do something ...
end ...

扩展阅读




  1. This is bullshit. 请看负责任那篇