component(component翻译)
构件(component)也称为组件
构件(component)也称为组件,是一个功能相对独立的具有可复用价值的软硬件单元。近年来,构件技术正在逐步应用于大型嵌入式系统的软件设计。
一、获取构件的方法包括:
(1)从现有构件中获得符合要求的构件,直接使用或作适应性(flexibility)修改,得到可重用的构件;
(2)通过遗留工程(legacy engineering),将具有潜在重用价值的构件提取出来,得到可重用的构件;
(3)从市场上购买现成的商业构件,即 COTS(Commercial Off-The-Shell)构件;
(4)开发新的符合要求的构件。
二、开发构件的策略:
分区:指的是将问题情景的空间分割成几乎可以独立研究的部分;
抽象:是对给定实践内执行指定计算的软/硬件单元的一种抽象;
分割:是将结构引入构件的行为,支持对行为性质进行时序推理。
三、主流构件标准包括:COBRA、COM/DCOM/COM+、EJB(答出其中两种即可)。
四、构件组装
构件组装是指将库中的构件经适当修改后相互连接,或者将它们与当前开发项目中的软件元素相连接,最终构成新的目标软件。构件组装技术大致可分为基于功能的组装技术、基于数据的组装技术和面向对象的组装技术。
(1)基于功能的组装技术
基于功能的组装技术采用子程序调用和参数传递的方式将构件组装起来。它要求库中的构件以子程序/过程/函数的形式出现,并且接口说明必须清晰。当使用这种组装技术进行软件开发时,开发人员首先应对目标软件系统进行功能分解,将系统分解为强内聚、松耦合的功能模块。然后根据各模块的功能需求提取构件,对它进行适应性修改后再挂接在上述功能分解框架(framework)中。
(2)基于数据的组装技术
基于数据的组装技术首先根据当前软件问题的核心数据结构设计出一个框架,然后根据框架中各结点的需求提取构件并进行适应性修改,再将构件逐个分配至框架中的适当位置。此后,构件的组装方式仍然是传统的子程序调用与参数传递。这种组装技术也要求库中构件以子程序形式出现,但它所依赖的软件设计方法不再是功能分解,而是面向数据的设计方法,例如 Jackson 系统开发方法。
(3)面向对象的组装技术
由于封装和继承特征,面向对象方法比其他软件开发方法更适合支持软件重用。在面向对象的软件开发方法中,如果从类库中检索出来的基类能够完全满足新软件项目的需求,则可以直接应用。否则,必须以类库中的基类为父类采用构造法或子类法生成子类。
看了这篇你将彻底了解组合模式
作者 | 静幽水
责编 | 郭芮
问题背景
假设,IT公司老板通过观察者模式和程序员小强和小华实现了通信,便于通知他们加班,还可以单独通知不同的内容,例如通知小强加班,通知小华去出差。但随着公司的规模慢慢变大,公司从只有两个程序员和一个秘书的公司成长为一个拥有研发部和市场部两个部门,十几位员工的公司。那这种情况下,之前的通知系统还好用吗?例如老板想要通知研发部经理和市场部经理来办公室开会,并且通知研发部经理手下的所有研发人员今晚加班赶项目进度,该如何实现呢?
首先,将公司里所有的人员抽象出一个Staff接口类,接口里是所有成员的共同属性和方法,如获取个人信息的方法和接收通知的方法。
Staff接口类
然后公司里的员工可以分为两类,一类是管理者,手下还有若干管理者或员工,另一类就是普通的员工,没有下属。首先定义管理者的接口:
管理者接口有四个方法,分别是增加和删除下属成员,获取下属信息和通知下属消息。
普通员工接口类,在这里指的当然就是程序员啦,只是一个空接口:
在来看普通员工(程序员)的实现类,有两个属性,分别是姓名和职位,虽然大家都是程序员,但也是有职位之分的。然后是接收通知方法和获取个人信息方法的实现,接收通知方法的实现很简单,就是把自己的名字和职位以及被通知的内容打印出来(这里打印姓名和职位是为了和管理者进行对比)。
接下来是管理者的实现,同样拥有姓名和职位两个属性,并且还有维护一个下属成员的列表,用来保存手下所有的员工对象。增加下属就是往列表中添加一个对象,删除就是从下属列表中将该对象移除。查看下属成员是将下属成员列表返回。同时还有通知下属和接收上级通知的方法,通知下属时会遍历下属成员列表,如果该下属是普通员工(程序员),调用程序员的接收通知的方法,如果手下是管理者,调用管理者的接收通知的方法,同时将通知再向下级传递。
最后写个客户端调用上面的方法,先创建一个大老板对象boss,然后一个研发部经理,两个研发部小组长和四个程序员,将程序员加到对应的组长名下,并将组长加到经理名下,最后将经理加到老板名下。老板发出通知,所有的普通员工今晚要加班,所有的管理者来会议室开会。
组织结构图如下:
程序运行结果:
上面程序的类图如下:
有何问题?
上面的程序乍一看似乎没有什么问题,而且我们也把管理者和普通员工类里的共性封装起来了,但有基础的同学或许看出来了,程序没有很好的进行代码复用,虽然把获取个人信息的getInfo方法和接收通知的doSomething方法在顶层接口中封装了,但它们在不同的实现类中代码完全一样(只是将个人信息和接收到的通知打印出来),为什么不抽象出来用抽象类实现呢?在这里就要了解一下接口和抽象类的异同点,以及它们分别在什么情况下使用。
1.相同点:
(1) 都是上层的抽象层
(2)都不能被实例化
(3 )都能包含抽象方法
(4)抽象类中的抽象方法必须全部被子类实现,如果没有全部实现,那么子类也必须是抽象类。接口中的方法也必须全部被子类实现,如果没有全部实现,子类必须是抽象类。
2.不同点:
(1)方法不同:在抽象类中除了抽象方法之外还可以写非抽象方法(但至少要有一个抽象方法),从而避免在实现类中重复写,提高代码复用性。接口中只能有抽象类(只是方法的声明,没有实现)。
(2)实现方法不同:java中只能单继承,即一个类只能继承一个抽象类。但一个类可以实现多个接口。
(3)抽象程度不同:由高到低,接口>抽象类>实现类。可以说抽象类是接口的中庸之道,我们在使用的时候应该优先选择抽象类。
(4)接口是对动作的抽象,而抽象类是对根源类别的抽象,接口强调的是有没有的关系,抽象类强调的是是不是的关系。例如猴子都会爬树和吃香蕉,这是猴子的共性,可以抽象出抽象类,每个子类都会实现这两个方法。但只有经过训练的猴子才会骑自行车,骑自行车这个方法就不能放在抽象类中,因为子类需要实现所有的抽象方法,明显不是所有猴子都会骑自行车,所有要将这个方法放在一个接口中,让那些会骑自行车的猴子实现这个接口。
(5)设计目的不同:接口是为了对类的行为进行约束,用来规定实现类有什么功能。抽象类是为了代码复用,当不同的类具有相同的行为时,并且这其中还有一部分的行为实现方式一致时,将这些类抽象出一个抽象类,在抽象类中将相同的方法实现,就达到了代码复用的目的。
(6) 接口是隐式抽象的,声明时没有必要使用abstract关键字,接口中的方法也是隐式抽象的,也没有必要使用abstract关键字。接口中的成员变量隐式为static final,而抽象类不是。
好了,再来看上面的类图,既然所有的员工都有获取个人信息和接收通知的方法,就没有必要将它们抽象出接口了,并且这两个方法的实现体在不同的实现类中是相同的,所有将他们抽象出抽象类更能体现代码的复用性。
解决方案
修改类图,将接口改成抽象类,如下:
Staff抽象类:
管理者Manager类:
普通员工Programmer类:
Client类保存不变,运行结果也和上面一致。
模式讲解
上面使用的模式就是组合模式(Composite),组合模式的定义:将对象组合成树型结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
上面的管理者和员工就是部分和整体的关系,符合树状结构。组合模式的通用类图:
Component:抽象的组件对象,定义组合对象的共有方法和属性,可以定义一些默认的行为或属性。这个抽象类既可以代表叶子对象,也可以代表组合对象,这样用户在操作的时候,对单个对象和组合对象的使用就具有了一致性。
Leaf:叶子节点对象,定义和实现叶子对象的行为,不再包含其他子节点对象。
Composite:组合对象,通常会存储子组件,定义包含子组件的那些行为,并实现在组件接口中定义的与子组件有关的操作。
Client:客户端,通过组件接口来操作组合结构里的组件对象。
组合模式的优点:
(1)统一了组合对象和叶子对象,局部和整体对于调用者来说没有区别,所有节点都是Component,例如在上面示例中的通知方法中, for(Staff s:subordinateList)语句中的subordinateList列表中,肯定有组合对象也有叶子对象,即有管理者也有普通员工,我们不需要区分,都看作是Staff类型。有同学会说,骗谁呢,你这里没区分下面不还是判断了吗,下面改写一下,很简单,以getInfo为例,在抽象类中不写实现,在叶子子类中只输出自己的信息,在组合子类中也是先输出自己的信息,然后判断下属列表是否为空,不为空说明还有下属,然后再遍历下属对象并用下属去调用getInfo方法,递归输出每个对象信息。
(2)节点自由添加,想添加一个组合节点或叶子节点只需要找到它的父节点就可以,非常容易扩展,符合开闭原则。
组合模式的缺点:
与依赖倒置原则冲突,就是在客户端创建的时候直接使用了实现类。
组合模式使用场景:
(1) 想要表示对象的部分与整体的层次结构,可以选择组合模式,把整体和部分的操作统一起来,使得层次结构实现更加简单。
(2)如果想统一的使用组合结构中的所有对象,可以选用组合模式。
新的问题
细心的同学应该发现了,既然说组合模式是要让用户对叶子对象和组合对象的使用具有一致性,但是在创建对象的时候却还是使用各自的实现类创建的,这就涉及到组合模式实现的两种方式:安全性和透明性。
安全性:安全性指客户在使用的时候不会发送误操作,能访问的方法都是被支持的方法。
透明性:透明性指客户在使用的时候不需要区分组合对象还是叶子对象。
简单来说,安全性的方式是将对组件的操作(如增加一个子组件,删除一个子组件,获取子组件)定义在组合类Composite中,这样叶子节点对象就不能使用这些功能(本身叶子对应就不应该有这些功能),就不会产生误操作的现象。上面的示例代码都是安全性方式的。但这会带来透明性的问题,客户在使用的时候必须区分到底使用的叶子对象还是组合对象,因为他们的功能是不同的。
透明性方式是将对组件的操作定义在抽象类中,这样客户端只需面对Component,不需要关系具体的组件类型。但这会带来安全性的问题,因为叶子对象也具有了操作组件的方法,客户就有可能误对叶子对象调用这些方法,这样的操作是不安全的。如上面的示例,用这种方式写就是普通员工也有发布通知的功能了,这显然是不允许的。
首先看一下透明方式的类图:
透明性具体代码如下,为了充分体现透明性,代码和上面的改动有些大:
抽象类Staff(相当于Component)
抽象类中定义了对员工操作的所有方法,包括增加,删除,查看和通知。还包括普通员工和管理者都有的获取个人信息方法和接收通知方法,这两个方法定义为抽象方法。
普通员工类(相当于Leaf)
这个类比较简单,就是增加了两个属性和实现了两个抽象方法。
管理者类(相当于Composite)
这个类比较复杂,处理实现了获取个人信息和接收通知的方法外,还重写了增加,删除,查看下属员工的方法,以及发布通知的方法。
客户端:
在这里能够看出,普通员工和管理者没有任何区别,客户端不需要区分组合对象和叶子对象了,统一使用组件对象(Staff),调用的方法也是在组件对象中定义的方法。
运行结果:
相关扩展
组合模式中的递归:指的是对象递归组合,对象本身的递归,在设计上称为递归关联,是对象关联关系的一种。理论上是没有层次限制的。
最大化Component定义:在透明性的组合模式中,能够看出组合对象和叶子对象的方法都被定义在了Component中,这其实是与类的设计原则相冲突的,一个父类应该只定义那些子类有意义的操作,而Component很多方法对于叶子对象没有意义。解决方法就是为这些方法提供默认实现,或者抛出不支持该功能的异常,如果子类需要这个方法就覆盖实现,不需要就不需要管。
父组件引用:在上面的示例都是从上到下的引用,也就是父到子的引用,而很多时候我们需要从下到上的引用,还是上面的例子,如果想要从普通的程序员找到他的小组长或者部门经理该怎么做呢?解决方法是在保持父组件到子组件引用的基础上,再添加保持子组件到父组件的引用。在Component中定义对父组件的引用,组合对象和叶子对象都继承这个引用。在组合对象添加子组件对象的时候,为子组件设置父组件引用,在组合对象删除一个子组件对象的时候,再重新设置相关子组件的父组件的引用。把这些实现到composite中,这样所有的子类都可以继承到这些方法,从而更容易的维护子组件到父组件的引用。由于篇幅关系,这里不再写代码。
环状引用:指的是对象之间的引用形成了一个环,一个对象经过若干次引用之后又包含了这个对象本身,就构成了一个环状引用,如A包含B,B包含C,C包含A.通常在设计组合模式时需要避免这种情况,否则容易出现死循环。但如果真的需要环状引用,就需要构建环状引用,并提供相应的检测和处理。
声明:本文为作者投稿,版权归其所有。
03 React组件(Component)
React组件,主要包括三部分:状态(state)、属性(props)和渲染(render)。
render是创建组件时唯一必须的方法,状态和属性都是可选的。通过setState方法更新state,组件会重新渲染组件的UI以及以此数据为属性的任何子组件。属性props是父组件传递给子组件的数据,更新属性就会自动更新接收该属性的任何组件。
React创建组件的两种方法:
函数组件,或叫函数式组件
Class 组件
- Class 组件必须有一个render()函数,它的返回值会被渲染为一个 React 元素
- 还需要从 React 中引入Component
以小写字母开头的元素代表一个 HTML 内置组件,比如 <div> 或者 <span> 会生成相应的字符串 'div' 或者 'span' 传递给 React.createElement(作为参数)。大写字母开头的元素则对应着在 JavaScript 引入或自定义的组件,如 <Foo /> 会编译为 React.createElement(Foo)。
我们建议使用大写字母开头命名自定义组件。如果你确实需要一个以小写字母开头的组件,则在 JSX 中使用它之前,必须将它赋值给一个大写字母开头的变量。
- 创建一个同名的 ES6 class,并且继承于 React.Component。
- 添加一个空的 render() 方法。
- 将函数体移动到 render() 方法之中。
- 在 render() 方法中使用 this.props 替换 props。
- 删除剩余的空函数声明。
参考链接:https://www.reactnative.cn/docs/intro-react
参考链接:https://zh-hans.reactjs.org/docs/jsx-in-depth.html#gatsby-focus-wrapper
阴阳师4月22日更新内容:帝释天上线技能调整,红莲华冕活动来袭[多图],阴阳师4月22日更新的内容有哪些?版本更新
2025-02-11四川电视台经济频道如何培养孩子的学习习惯与方法直播在哪看?直播视频回放地址[多图],2021四川电视台经济频
2025-02-11湖北电视台生活频道如何培养孩子的学习兴趣直播回放在哪看?直播视频回放地址入口[多图],湖北电视台生活频道
2025-02-11
用户评论
看来这篇文章主要是聊那些基础部件或者元件啊!
有16位网友表示赞同!
终于看到关于组件的文章了,我一直在找这种类型的文章呢。
有9位网友表示赞同!
希望能从文章中学习到如何搭建复杂系统的知识。
有10位网友表示赞同!
文章说到的是软件组件吗?这方面挺想了解一下的。
有11位网友表示赞同!
是不是讲不同硬件的组合方式啊?很有意思,我会去看一看。
有5位网友表示赞同!
组件设计真是至关重要啊,期待作者分享经验!
有10位网友表示赞同!
各种类型的部件都有哪些用处呢? 挺好奇的文章主题哦。
有8位网友表示赞同!
这种文章应该能帮到很多开发人员吧,他们经常要处理各种组件嘛。
有11位网友表示赞同!
组件的优化和测试也是很关键的任务啊,希望文章能涉及到这些方面。
有13位网友表示赞同!
如果能讲一些组件设计的基本原则就好了,这样对学习才有帮助。
有17位网友表示赞同!
感觉这篇文章内容应该挺专业性的,需要稍微花点时间才能理解。
有11位网友表示赞同!
我喜欢技术类文章,关于组件的讲解总是很有启发性的。
有15位网友表示赞同!
不知道文章会介绍哪些类型的组件?硬件、软件都行吗?
有13位网友表示赞同!
希望文章能讲清楚组件之间的交互方式,这很重要啊!
有14位网友表示赞同!
阅读这篇文章之后可以更深入地了解到系统是如何构建的吗?
有10位网友表示赞同!
是不是会分享一些组件开发的工具和资源呢?我一直在找这类信息。
有13位网友表示赞同!
感觉这篇文章会很有实用性,能让我在工作中获得帮助。
有9位网友表示赞同!
期待作者能用通俗易懂的方式讲解组件技术!
有12位网友表示赞同!
文章要讲清楚不同组件之间的关系和协作模式吗?这才是关键点。
有19位网友表示赞同!