白话设计——从类关系说起

温故知新,最近更多的是研究和开发各种类库,对设计的是有些感触.以前在大学的时候,虽然知道,但是总归是欠缺经验的,现在,我尝试用最通俗易懂的方式说出来.

所谓的设计不正是采用恰当的方式组织雷类关系么?因此谈设计我认为首先要从类之间的关系开始说起.

在java开发中,有很多时候我们是在不断的处理类与类之间关系,其中这六种关系是:依赖、关联、聚合、组合、继承、实现,他们的耦合度依次增强,其在UML的表示如下:


这里写图片描述

下面我们分别对这几种关系进行说明.

依赖

在实际生活中我们做任何一件事情几乎都需要借助其他物体的帮助,换句话说,我们依赖于其他的物体生活。比如:小明要开车,小明要吃饭,小明要生活等等,不难想象出依赖关系是现实世界中最普通的关系。对于以面向对象为思想的语言世界来说,依赖也是最普遍和常见的关系。

在代码层次上,依赖关系多表现为函数的参数.

public class Person{
    public void drive(Car car){
        //
    }
}

UML表示:


这里写图片描述

关联

如果说依赖关系讲求的临时性,偶然性的话,那么关联关系则是一种持久性的关系。为什么这么说呢?
小明吃饭借助筷子,这种关系只存在小明吃饭的情况下,一旦小明不吃饭了,那么这种依赖关系也就终止了。
与依赖关系不同,关联对象的双方地位同级,存在长期,固定的对应关系,即关联是一种强依赖。关联关系共分为两种:单向关联和双向关联。所谓单向关联通俗点讲就是“你中有我,但我中未必有你”,比如小明拥有一辆车(注意和小明开车进行区分),但车这个对象可不拥有你啊。和单向关联相对应的是双向关联,也即是"你中有我,我中有你",比如夫妻就是一种双向关联.

在代码层次上,关联关系表现为对象作为另一个类的成员变量.

单向关联

public class Person{
    private Car car;
    public void setCar(Car car){
        this.car=car;
    }
}

UML表示:


这里写图片描述

双向关联

public class Husband{
    private Wife wife=new Wife();
    
    public void say(){
        System.out.println("my wife name:"+wife.getName());
    }
    
}

public class Wife{
    private Husband husband=new Husband();
    
    public void say(){
        System.out.println("my husband name:"+husband.getName());
    }
    
}

UML表示:


这里写图片描述

聚合

聚合关系是一种强关联关系,两者之间最主呀的区别是在语意上:聚合之间的关系更像是"整体-部分",有点组装的含义,而关联关系的对象间是相互独立的,不存在组装关系.
在现实世界中,分子是由原子组成的,汽车是由各种零部件组成的等,这都是聚合关系的最好说明.这里要注意,组成A类型分子的原子也可以组成B类型的分子,这说明什么呢?也就是部分可以单独存在,换句话说就是整体和部分两者的生命周期不是同步的.比如:水分子是由氧原子和氢原子组成的,你不能说没有水分子就没有氧原子和氢原子吧.

在代码层次上,聚合和关联两者的形式一致,都表现为成员变量.

public class Car{
    private Tyre tyre;
    private Engine engine;
    
    public void setTyre(Tyre tyre){
        this.tyre=tyre;
    }
    
    public void setEngine(Engine engine){
        this.engine=engine;
    }
}

UML表示:


这里写图片描述

有些人写成以下样子:

public class Car{
    private Tyre tyre=new Tyre();
    private Engine engine=new Engine();
    
    
}

咋眼一看在代码层次上符合啊,那这算不算是聚合关系呢?首先呢,我们肯定的说这是聚合关系.但仅仅是形势上聚合的关系.为什么这么说呢?

我们从真实世界中抽象汽车这个概念,进而将其转化为软件世界中的Car,这也是java中提倡的面向对象编程的,但是呢,在从真实世界到软件世界的这个过程中需要保证物体静态属性和动态属性没变.什么意思呢,换言之就是,你将真实世界中的汽车转成换成软件世界中Car,反过来,也要保证从软件世界中Car能够转换成真实世界中的汽车.如果不能保证转换的一致性,那么就说明,抽象过程中出现了问题.

现在将上边的代码中的Car转成现实世界中的汽车,我们发现转换后的汽车竟然不能换车轮了?这可能吗?很显然,在对抽象汽车到Car这个类的过程中出现了问题.那么应该怎么样的呢?
除了一开始我们写的那样,还可以如下:

public class Car{
    private Tyre tyre=new Tyre();
    private Engine engine=new Engine();
    
    public void setTyre(Tyre tyre){
        this.tyre=tyre;
    }
    
    public void setEngine(Engine engine){
        this.engine=engine;
    }
}


组合

组合和聚合非常类似,都表示的"整体-部分",但是组合要求整体和部分的生命周期是同步的,部分不能脱离整体而存在.不难发现,组合是一种强聚合关系.比如,人这个生命体由不同器官构成,其中我们拿心脏来说一下,人要活着必须依靠心脏,心脏不能脱离人这个生命体,两者一旦分开,都会死亡.
在代码层次上,通常表现为类的成员变量,除此之外还要求这个成员变量在构造函数中创建.

public class People{
    private Heart heart;
    
    public People(){
        heart=new Heart();
    }
}

UML表示:


这里写图片描述

到现在我们从微观的角度了解依赖,关联,聚合和组合这四种关系,从宏观上来说,这四种关系体现的都是对象与对象之间的依赖,因此在某些方面,我们也同依赖来涵盖这四种关系.在很多文章中,并没有说到这一点,这也造成,很多情况下,大家对这几个概念探地的时候感到很疑惑.

从真实世界中来看,对象与对象之间的关系其实可以分为两类,一是上边宏观所说的依赖,另一种则是我们下面要谈的泛化


泛化

在开始解释泛化之前,先来从extends说起:

extends的意思是延伸,扩展,继承.从这个词的角度来说,子类应该分为两层意思:

一种是增强原有类的功能,这体现的不是生物界的"父与子"关系.比如我现在拥有一个工具类Tools,现在我想要增强该工具类,按照开闭原则,我定义了UpdateTools extends Tools,此时你就不能说UpdateTools是Tools的"孩子",因为你发现这里的UpdateTools仅仅是增强原有Tools类的功能,作为功能扩展类来的.此时,我们称其为扩展比较合适.

另一种则就是体现生物界的"父与子",即子类和父类在某些行为或者属性的表现不一样.这时候,用单词inherit来表示更合适,也就是我们常说的继承的意思.

到现在,相信你已经明白了extends的含义.其实,实际中,我们使用继承的目的就是为了扩展,因此,可不做深究.
之所以谈到这一点,是因为去年带过的一个实习生仅仅因为不理解extends中的两层,而觉得通过UpdateTools扩展Tools是有问题的.

下面我们在来说泛化.
泛化表示一个类(父类或接口)与其一个或者多个变体之间的关系.简单的来说泛化表示类与类之间的扩展,接口与接口的扩展,类与接口之间的实现关系.
在java中用extends来表示扩展,用implements表示实现关系.

扩展:

public class Tools{
    public void print(){
        //do 
    }
}

public class UpdateTools extens Tools{
    public void printError(){
        //do
    |
    
}

继承:

public class Father{
    public void getName(){
        //do
    }
}

public class Son{
    public void other(){
        //do
    }
}

UML表示:


这里写图片描述

实现:

public interface UserService{
    void execute();
}

public class UserServiceImpl implements UserService{

    @override
    void execute(){
        //do
    }
}


UML表示:


这里写图片描述

到现在,相信你对类关系有了清晰的理解了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,780评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,424评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,397评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,576评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,997评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,945评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,107评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,850评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,625评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,804评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,285评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,613评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,291评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,164评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,963评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,096评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,886评论 2 278

推荐阅读更多精彩内容