什么是合成复用原则?
合成复用原则(Composite/Aggregate Reuse Principle,CARP)指尽量使用对象组合(has-a)或对象聚合(contanis-a)的方式实现代码复用,而不是用继承关系达到代码复用的目的。合成复用原则可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较小。
合成复用原则有什么作用?
合成复用原则分为继承复用和合成复用,我们来看看这两种之间的区别
继承复用
1、破坏类的封装性
2、子类和父类耦合度高
3、限制复用的灵活性
合成复用
1、维持类的封装性
2、降低耦合度
3、复用的灵活性高
案例分析
手机按“功能”可分为智能手机、老人机等,按“颜色”可分为黑色、白色、粉色等。如果同时考虑使用继承复用、合成复用我们来具体看下它们如何实现
方案一:继承复用
1、定义手机抽象类
1
2
3
4
| abstract class IPhone {
// 打电话功能
void call();
}
|
2、苹果手机实现类
1
2
3
4
5
6
| class ApplePhone extends IPhone {
@override
void call() {
print("苹果手机打电话");
}
}
|
3、诺基亚手机实现类
1
2
3
4
5
6
| class NokiaPhone extends IPhone {
@override
void call() {
print("诺基亚手机打电话");
}
}
|
4、苹果手机颜色实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class WhiteApplePhone extends ApplePhone {
@override
void call() {
print("白色的苹果手机打电话");
}
}
class BlackApplePhone extends ApplePhone {
@override
void call() {
print("黑色的苹果手机打电话");
}
}
class PinkApplePhone extends ApplePhone {
@override
void call() {
print("粉色的苹果手机打电话");
}
}
|
5、诺基亚手机颜色实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class WhiteNokiaPhone extends NokiaPhone {
@override
void call() {
print("白色的诺基亚手机打电话");
}
}
class BlackNokiaPhone extends NokiaPhone {
@override
void call() {
print("黑色的诺基亚手机打电话");
}
}
class PinkNokiaPhone extends NokiaPhone {
@override
void call() {
print("粉色的诺基亚手机打电话");
}
}
|
6、使用
1
2
3
4
5
6
7
| void main(List<String> args) {
IPhone whiteApplePhone = WhiteApplePhone();
whiteApplePhone.call();
IPhone whiteNokiaPhone = WhiteNokiaPhone();
whiteNokiaPhone.call();
}
|
7、运行结果
1
2
3
4
| Connecting to VM Service at http://127.0.0.1:51259/FmL9R3fZuN0=/
白色的苹果手机打电话
白色的诺基亚手机打电话
Exited
|
8、完整代码
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
| void main(List<String> args) {
IPhone whiteApplePhone = WhiteApplePhone();
whiteApplePhone.call();
IPhone whiteNokiaPhone = WhiteNokiaPhone();
whiteNokiaPhone.call();
}
abstract class IPhone {
// 打电话功能
void call();
}
class ApplePhone extends IPhone {
@override
void call() {
print("苹果手机打电话");
}
}
class WhiteApplePhone extends ApplePhone {
@override
void call() {
print("白色的苹果手机打电话");
}
}
class BlackApplePhone extends ApplePhone {
@override
void call() {
print("黑色的苹果手机打电话");
}
}
class PinkApplePhone extends ApplePhone {
@override
void call() {
print("粉色的苹果手机打电话");
}
}
class NokiaPhone extends IPhone {
@override
void call() {
print("诺基亚手机打电话");
}
}
class WhiteNokiaPhone extends NokiaPhone {
@override
void call() {
print("白色的诺基亚手机打电话");
}
}
class BlackNokiaPhone extends NokiaPhone {
@override
void call() {
print("黑色的诺基亚手机打电话");
}
}
class PinkNokiaPhone extends NokiaPhone {
@override
void call() {
print("粉色的诺基亚手机打电话");
}
}
|
9、分析
我们通过继承复用原则对手机的需求进行了实现,但是这样破坏了类的封装性,而且子类和父类的耦合度太高导致了复用的灵活性不高。
方案二:合成复用
1、定义手机颜色抽象类和实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| abstract class IPhoneColor {
late String color;
IPhoneColor(this.color);
}
class WhitePhoneColor extends IPhoneColor {
WhitePhoneColor(String color) : super(color);
}
class BlackPhoneColor extends IPhoneColor {
BlackPhoneColor(String color) : super(color);
}
class PinkPhoneColor extends IPhoneColor {
PinkPhoneColor(String color) : super(color);
}
|
2、定义手机抽象类
1
2
3
4
5
6
7
| abstract class IPhone {
// 手机颜色
late IPhoneColor phoneColor;
IPhone(this.phoneColor);
// 打电话功能
void call();
}
|
3、定义苹果手机实现类
1
2
3
4
5
6
7
8
9
| class ApplePhone extends IPhone {
ApplePhone(IPhoneColor color):super(color);
@override
void call() {
print("苹果手机打电话");
}
}
|
4、定义诺基亚手机实现类
1
2
3
4
5
6
7
8
| class NokiaPhone extends IPhone {
NokiaPhone(IPhoneColor color) : super(color);
@override
void call() {
print("诺基亚手机打电话");
}
}
|
5、使用
1
2
3
4
5
6
7
8
9
| void main(List<String> args) {
ApplePhone applePhone = ApplePhone(WhitePhoneColor("白色"));
applePhone.call();
print(applePhone.phoneColor.color);
NokiaPhone nokiaPhone = NokiaPhone(PinkPhoneColor("粉色"));
nokiaPhone.call();
print(nokiaPhone.phoneColor.color);
}
|
6、运行结果
1
2
3
4
5
6
| Connecting to VM Service at http://127.0.0.1:51924/yuNcRaUGX4Q=/
苹果手机打电话
白色
诺基亚手机打电话
粉色
Exited
|
7、完整代码
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
| void main(List<String> args) {
ApplePhone applePhone = ApplePhone(WhitePhoneColor("白色"));
applePhone.call();
print(applePhone.phoneColor.color);
NokiaPhone nokiaPhone = NokiaPhone(PinkPhoneColor("粉色"));
nokiaPhone.call();
print(nokiaPhone.phoneColor.color);
}
abstract class IPhone {
// 手机颜色
late IPhoneColor phoneColor;
IPhone(this.phoneColor);
// 打电话功能
void call();
}
class ApplePhone extends IPhone {
ApplePhone(IPhoneColor color):super(color);
@override
void call() {
print("苹果手机打电话");
}
}
class NokiaPhone extends IPhone {
NokiaPhone(IPhoneColor color) : super(color);
@override
void call() {
print("诺基亚手机打电话");
}
}
abstract class IPhoneColor {
late String color;
IPhoneColor(this.color);
}
class WhitePhoneColor extends IPhoneColor {
WhitePhoneColor(String color) : super(color);
}
class BlackPhoneColor extends IPhoneColor {
BlackPhoneColor(String color) : super(color);
}
class PinkPhoneColor extends IPhoneColor {
PinkPhoneColor(String color) : super(color);
}
|
8、分析
这里我们采用组合复用的方式对手机的需求进行了优化,手机颜色和手机区别开来并通过组合复用的方式进行重构,这样既维持了类的封装性并降低了类与类之间的耦合度,而且提高了代码的灵活性。
总结
在我们遵守合成复用原则的同时,尽量能使用合成复用就不要使用继承复用的方式,不然破坏了类的封装性,而且子类和父类的耦合度太高导致了复用的灵活性不高。