在读设计模式, 做了简单的笔记, 并没有深入设计模式总结.

#interface

首先, 温习一下Java中的接口技术(interface), 接口主要用于描述类具体有什么功能, 但并不给出每个功能的具体实现(类似与iOS编程中的协议的概念)

1
2
3
public interface Comparable<T> {
int compareTo(T other);
}

如果类遵从特定的接口, 那就必须实现具体的业务逻辑(类似于iOS编程中, 作为delegate就必须具体实现协议定义)

  • 接口所有方法自动属于public
  • 接口不能含有实例域, 但可以包含常量, 不能在接口中实现方法(可以看做没有实例域的抽象类)
  • 实现接口时需要声明为public
  • 不能用new实例化一个接口, 但能声明接口的变量
  • 一个类只能使用一个抽象类(Java不支持多继承), 却可以使用多个接口
1
2
3
4
5
6
//某个类要实现一个接口
class Student implements Comparable<Student> {
public int CompareTo(Student s) {
//具体实现
}
}

#设计原则

设计告诉我们如何组织类和对象以解决某种问题

  • 找出应用需要变化之处, 把它们独立出来, 不要和那些不需要变化的代码混在一起
  • 针对接口编程 而不是针对实现编程
  • 多用组合, 少用继承

#策略模式(Strategy Pattern)

策略模式定义了算法族, 分别封装起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户

  • 策略模式的核心是动态绑定
  • 策略模式将不断变化的部分封装为一个接口, 可以不同变化进行接口的具体实现
  • 在使用到变化的类中增加一个声明一个接口的变量(注意是接口, 不是接口的一些具体实现, 这里用到动态绑定)
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//抽象类, 用于被其他子类继承, 重写其中的方法
public abstract class Duck {
//生成两个接口的实例变量
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
//初始化方法
public Duck() {
}
//接口变量的set方法
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
public abstract void display();
public void performFly() {
flyBehavior.fly(); //执行动态绑定的地方
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("All ducks float, even decoys!");
}
}
//定义一个接口
public interface FlyBehavior {
public void fly(); //接口中的方法并不进行具体实现
}
//类对接口的具体实现
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("I can't fly!");
}
}
public class FlyWithWings implements FlyBehavior {
//实现接口的具体类
public void fly() {
System.out.println("I'm flying !");
}
}
//定义另一个接口
public interface QuackBehavior {
public void quack(); //接口中的方法并不具体实现
}
//类实现具体的接口
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("<<MuteQuack!>>");
}
}
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("Quack!");
}
}
public class Squeak implements QuackBehavior {
public void quack() {
System.out.println("Squeak!");
}
}

通过抽象类, 得到一个真正的子类

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
public class MallardDuck extends Duck {
public MallardDuck() {
//分别给两个接口变量, 赋值需要的类实例
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display() {
System.out.println("I'm a real Mallard duck!");
}
}
//测试类
public class MiniDuckSimulator {
public static void main(String[] args) {
//调用MallardDuck类中的构造方法进行接口变量的初始化
Duck mallard = new MallardDuck(); //获得一个类实例
/*
此处类实例赋值给Duck变量, 直到运行时才知道Duck中
具体的对象类型, 得到MallarDuck类, 然后运行下面两个已
经在MallardDuck中赋值的两个接口类的实例
*/
mallard.performFly(); //真正执行的是FlyWithWings类中中fly方法
mallard.performQuack(); //真正执行的是Quack类中的quack方法
}
}

#观察者概念

主题 + 观察者 = 观察者模式

主题对象管理某些数据, 当主题内的数据改变, 就会通知观察者, 观察者已经向主题注册, 这样观察者在每次主题数据改变时都能收到更新

观察者模式定义了对象之间的一对多依赖(一个主题, 多个观察者), 当一个对象改变状态, 他的所有依赖者都会收到通知并更新

#观察者模式(Observer Pattern)

首先定义主题, 观察者, 观察者抽象行为接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Subject {
//观察者向主题注册
public void registerObserver(Observer o);
//移除观察者
public void removeObserver(Observer o);
//通知所有观察者
public void notifyObservers();
}
public interface Observer {
//主题进行调用, 通知观察者数据以更新
public void update(float temp, float humidity, float pressure);
}
public interface DisplayElement {
//每个观察者对于数据变化的反应不同, 可以抽象出来一个接口
public void display();
}
  • 定义实现主题接口的类(作为主题)
  • 定义实现观察者接口的类(作为观察者)
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class WeatherData implements Subject {
//WeatherData作为主题, 实现Subject的接口
private ArrayList observers; //记录观察者
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList(); //初始化
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i > 0) {
observers.remove(i);
}
}
@Override
public void notifyObservers() {
for (int i = 0; i < observers.size(); i++) {
Observer observer = (Observer)observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
//数据发生更新时此方法会被调用, 通知所有的观察者数据已更新
public void measurementsChanged() {
notifyObservers();
}
//数据更新
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
//作为观察者实现了观察者接口, 同时实现display接口
public class CurrentConditiondDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditiondDisplay(Subject weatherData) {
this.weatherData = weatherData; //获取主题对象, 保留Subject的引用
weatherData.registerObserver(this); //将观察者注册到主题中
}
//实现Observer的update接口
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
//实现DisplayElement的接口
@Override
public void display() {
System.out.println("Current condition: " + temperature
+ "F degresss and " + humidity + "% humidity");
}
}

测试类

1
2
3
4
5
6
7
8
9
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
//初始化观察者, 并传入主题的引用
CurrentConditiondDisplay currentDisplay = new CurrentConditiondDisplay(weatherData);
//观察者数据变化, 会调用measurementsChanged()方法, 然后会调用notifyObservers()通知所有已注册的观察者
weatherData.setMeasurements(80, 65, 30.4f);
}
}

Java本身自带一套观察者模式, 其中Observable相当于Subject, 不过Observable是一个, 而不是接口, Observer是一个观察者接口

分析认为: iOS中按钮的点击事件使用了观察者模式, 按钮被点击后, 通知所有观察者, 合适的观察者对按钮点击事件进行处理

#参考连接