学习类和类之间的关系是学习设计模式的基础。总是有些同学对这六种关系说不清楚,本文就用一个小小的爱情故事来让我们重新学一下这个知识点吧。
1 依赖
我是一个男孩,你是一个女孩。命运总是在不经意间,让你我在茫茫人海中相遇。我见过书店里淡雅恬静的你、也见过舞会上青春飞扬的你。我曾被你的大小姐脾气怼得无言以对,也曾被你的古怪精灵逗得忍俊不禁。这个时候,我们之间的关系叫做依赖。
1.1 UML图
1.2 代码
package relationship.love.ver1; public class I { public void see(You you) { System.out.println(this + "看见" + you); } public void party() { You you = new You(); System.out.print(this + "和" + you); you.dance(); } public void angry() { System.out.println(this + "遇到你的" + You.badTemper); } public void happy(You you) { System.out.print(this + "遇到" + you); you.happy(); } @Override public String toString() { return "我"; } }
package relationship.love.ver1; public class You { @Override public String toString() { return "你"; } public static String badTemper = "坏脾气"; public void dance() { System.out.println("跳舞"); } public void happy() { System.out.println("高兴"); } }
package relationship.love.ver1; public class Tester { public static void main(String[] args) { I i = new I(); You you = new You(); i.see(you); i.party(); i.angry(); i.happy(you); } }
输出:
我看见你 我和你跳舞 我遇到你的坏脾气 我遇到你高兴
点评:
代码中尝试着演示了依赖关系的各种可能情况。
1.3 知识点
A依赖B的关系是一种弱的use(使用)关系,一般带有临时性,B的改变可能会影响到A。
在代码上,一般表现为下面的形式:
A方法的参数是B
A方法内的局部变量是B
A直接引用B的静态成员
2 关联
后来,我们成了朋友,互相加了彼此的微信。渐渐地,我习惯了不经意间脱口而出你的名字,习惯了只要遇到一些开心的或不开心的事情就给你打个聊不完的电话。这个时候,我们之间的关系叫做关联。
2.1 UML图
或
2.2 代码
package relationship.love.ver2; public class I { private You you; public You getYou() { return you; } public void setYou(You you) { this.you = you; } public void longPhone() { System.out.print(this + "和" + you + "打电话"); } @Override public String toString() { return "我"; } }
package relationship.love.ver2; public class You { @Override public String toString() { return "你"; } }
package relationship.love.ver2; public class Tester { public static void main(String[] args) { I i = new I(); You you = new You(); i.setYou(you); i.longPhone(); } }
输出:
我和你打电话
点评:
这里只展示了单向关联关系,你可以尝试着写一下双向关联关系。
2.3 知识点
A关联B的关系是一种强的use(使用)关系,一般带有永久性,B的改变可能会影响到A。
在代码上,一般表现为下面的形式:
A类的属性是B
关联关系可以是单向的,也可以是双向的
3 内聚
终于,我向你表白了,我们顺理成章的成为了一对恋人。美中不足的是,两个城市之间的距离让我们总是聚少离多。这个时候,我们之间的关系叫做内聚。
3.1 UML图
3.2 代码
package relationship.love.ver3; public class I { private You you; public You getYou() { return you; } public void setYou(You you) { this.you = you; } public void loving() { System.out.print(this + "和" + you + "恋爱中"); } @Override public String toString() { return "我"; } }
package relationship.love.ver3; public class You { @Override public String toString() { return "你"; } }
package relationship.love.ver3; public class Tester { public static void main(String[] args) { I i = new I(); You you = new You(); i.setYou(you); i.loving(); } }
输出:
我和你恋爱中
点评:
仅仅从代码来看,内聚关系和关联关系也差不多,需要从语义的层次进行区分,内聚关系是has的关系,关联关系是use的关系。
3.3 知识点
A内聚B的关系是一种弱的has(拥有)关系,即常用的has-a的关系。一般带有永久性,B的改变一般会影响到A。
在代码上,一般表现为下面的形式:
Ø A类的属性是B
Ø A和B的生命周期一般不同
Ø A内聚B并不意味着A唯一拥有B
4 组合
后来,我们结婚了,一起走进了婚姻的殿堂,正式组成了一个家庭。这个时候,我们和我们的家庭之间的关系叫做组合。
4.1 UML图
4.2 代码
package relationship.love.ver4; public class We { @Override public String toString() { return "我们"; } private Family family = new Family(); public void live() { System.out.println(this + "的" + family + ",快乐的生活。"); } }
package relationship.love.ver4; public class Family { @Override public String toString() { return "家庭"; } }
package relationship.love.ver4; public class Tester { public static void main(String[] args) { We we = new We(); we.live(); } }
输出:
我们的家庭,快乐的生活。
点评:
内聚关系和组合关系的区别在于生命周期的控制不同。
4.3 知识点
A组合B的关系是一种强的has(拥有)关系,即常用的contains-a的关系。一般带有永久性,B的改变一般会影响到A。
在代码上,一般表现为下面的形式:
Ø A类的属性是B
Ø A管理B的生命周期
Ø A组合B意味着A唯一拥有B
5 实现
我小心地呵护着我们的婚姻,在公司,我是一个好员工;在家里,我是一个好丈夫。我同时实现了员工和丈夫两个接口,这种关系叫做实现。
5.1 UML图
5.2 代码
package relationship.love.ver5; public interface IEmployee { public void work(); }
package relationship.love.ver5; public interface IHusband { public void love(); }
package relationship.love.ver5; public class I implements IEmployee, IHusband{ @Override public String toString() { return "我"; } @Override public void work() { System.out.println(this + "努力工作"); } @Override public void love() { System.out.println(this + "全心爱你"); } }
package relationship.love.ver5; public class Tester { public static void main(String[] args) { I i = new I(); i.work(); i.love(); } }
输出:
我努力工作 我全心爱你
点评:
一个类可以实现多个接口。
5.3 知识点
B实现A的关系是一种弱is(是)关系,一般带有永久性,A的改变一定会影响到B。
在代码上,B一般表现为下面的形式:
B类实现了A接口
Java关键字是implements
B可以实现多个接口
6 继承
再后来,我们生了一个漂亮的宝宝,孩子继承了我们俩的优点。我们和我们的孩子之间的关系叫做继承。
6.1 UML图
6.2 代码
package relationship.love.ver6; public class I { @Override public String toString() { return "我"; } public void brave() { System.out.println("勇敢"); } }
package relationship.love.ver6; public class You { @Override public String toString() { return "你"; } public void beautiful() { System.out.println("美丽"); } }
package relationship.love.ver6; public class Children extends I { class ChildrenYou extends You { @Override public void beautiful() { super.beautiful(); System.out.println("可爱");; } } You makeYou() { return new ChildrenYou(); } }
package relationship.love.ver6; public class Tester { public static void main(String[] args) { Children children = new Children(); children.brave(); children.makeYou().beautiful(); } }
输出:
勇敢 美丽 可爱
点评:
Java不支持多继承。但是java有局部类的概念,事实上弥补了这个问题。尽管这种支持不是很完美,但比起C++为支持多继承而引入的各种陷阱,Java对多继承的支持也不失为一种优雅的解决方案。
6.3 知识点
B继承A的关系是一种强is(是)关系,即常用的is-a的关系。一般带有永久性,A的改变一定会影响到B。
在代码上,B一般表现为下面的形式:
B类是A类的子类
Java关键字是extends
Java中只允许单继承,不允许多继承,但是Java中有内部类,可以模拟多继承
C++中允许多继承
7 总结
本来故事到这里就可以结束了,但是以一个A型血完美主义者的眼光来看,我尝试着解决最后一个问题:为什么类和类之间的关系是6种?不多也不少。
我是这样来理解这个问题的。从距离的角度来说,类之间的关系可以分为远(use)、近(has)和距离为0(is)三种。每种距离又可以进一步分为弱关系和强关系。这样的一个二维矩阵正好就是6种关系啦。
好啦,今天的复习就到这里啦。记住我们的口号是:“好好学习,天天向上,每天进步一点点”。