整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

领域驱动设计(DDD),用了一个礼拜时间给大家整理干

领域驱动设计(DDD),用了一个礼拜时间给大家整理干货

们为什么需要领域驱动设计

在说什么是领域驱动设计之前,我觉得需要先说一下我们为什么需要领域驱动,我个人认为领域驱动设计对于研发来说改进点主要有下面三个:

  1. 从大泥球风格中解脱出来,控制代码复杂度
  2. 回归面向对象编程本质,而不是面向过程编程
  3. 专注于业务,实现不同业务领域解偶

什么是领域驱动设计

领域驱动设计(DDD)是一种软件设计思路,领域指的是业务领域,比如银行业务领域,医药销售领域;不同于传统以数据表为中心的建模方式,它以业务领域为中心来建模,能促使我们以正确的方式使用面向对象,建立饱满的领域对象。

在进行领域建模和开发时我们主要需要关注以下几点:

  1. 和领域专家一起构建一套通用语言,团队成员使用通用业务语言进行交流;
  2. 关注领域的战略设计,DDD的战略设计从更高层次抽象系统,划分出不同的系统和业务关注点,战略设计包含:领域/子域划分、通用语言的构建、限界上下文定义以及架构风格选择等;
  3. 实现DDD的战术设计,战术设计主要包含:领域对象(实体、值对象、聚合)、模块、领域服务、工厂等;

下面的思维导图是领域驱动设计需要掌握的一些点:

Tips:

1.领域驱动设计是2004年Eric Evans在《领域驱动设计:软件核心复杂性应对之道》这本书中提到的,DDD的出现是为了应对复杂业务场景下软件越来越复杂问题;也就是说通过DDD可以将软件的复杂度控制在合理的范围内。

2.领域驱动设计主要解决的是业务复杂度问题(避免大泥球风格:大泥球风格就是没有任何清楚的结构,例如随意共享的数据,随意全局化的数据结构。这样风格的系统可维护性(maintainability)和可扩展性(extensibility)都很差,最终导致整个系统难以改动,维护不下去),如果业务不复杂,则不需要使用DDD方式来处理(推荐用三层架构)。

领域驱动设计的优缺点

领域驱动设计的优缺点很明显,我这边整理了几个优缺点,供参考。

优点:

  1. 由领域专家进行领域模型设计,通过业务驱动开发而不是数据库设计来驱动项目开发,业务逻辑更加清晰;
  2. 再次强调了面向对象编程的重要性,减少面向过程编程(提高内聚性、降低上下文之间耦合);
  3. 对单元测试(自测)比较友好;

缺点:

  1. 需要有对DDD比较精通的人员进行领域的建模,如果建模不当,后续会比较麻烦;
  2. 对开发人员要求比较高,开发人员需要理解DDD才能进行开发;
  3. DDD本身概念性的东西比较多,有些概念不好理解,需要长时间的历练才能很好的掌握DDD;

如何进行领域建模

按照实现领域驱动设计一书中描述的DDD步骤主要有4步:

  1. 根据业务需求划分出初步的领域和限界上下文,以及上下文之间的关系;
  2. 进一步分析每个上下文内部,识别出哪些是实体,哪些是值对象;对实体、值对象进行关联和聚合,划分出聚合的范畴和聚合根;
  3. 为聚合根设计仓储,并思考实体或值对象的创建方式;
  4. 在工程中实践领域模型,并在实践中检验模型的合理性,倒推模型中不足的地方并重构。

划分领域和限界上下文

提炼问题域

软件开发实际作用就是为客户解决问题或者软件升级变革,所以在领域中我们划分了问题空间和解空间两个纬度空间,用于描述客户的问题(需求)和如何解决问题(解决方案)。

问题的来源:

  1. 客户痛点需求:比如电脑蓝屏、文档忘记保存等。
  2. 行业变革:移动支付、网购等。

问题域划分

首先我们需要对问题域进行拆分,拆分的理念就是由大化小,逐个击破。拆分完毕问题空间,我们需要做到逐一击破,为每一个问题形成一套落地解决方案。一个问题对应一个答案,解空间与问题空间基本上应该是一一对应的。

构建限界上下文

我们给出的解方案是一个个限界上下文,一个限界上下文负责应对其对应的问题进行解决,承载了该问题中的业务知识及规则。限界上下文是解决某一类问题的单一功能模块,例如订单限界上下文,处理开单、通知订单状态等一切与订单关联的功能。

随着问题的划分,将领域拆分成了不同的子域,每个子域有其独有的业务知识,而这些知识需要靠一门统一语言来描述。而不同限界上下文间的统一语言是相互独立的。可能在不同的限界上下文有同样的名词,但同样的名词在不同的限界上下文中可能表示的不是同一事物,即使是同一事物可能其在不同上下文中的关注点也不一致。

限界上下文之间的映射关系:

  • 合作关系(Partnership):两个上下文紧密合作的关系,一荣俱荣,一损俱损。
  • 共享内核(Shared Kernel):两个上下文依赖部分共享的模型。
  • 客户方-供应方开发(Customer-Supplier Development):上下文之间有组织的上下游依赖。
  • 遵奉者(Conformist):下游上下文只能盲目依赖上游上下文。
  • 防腐层(Anticorruption Layer):一个上下文通过一些适配和转换与另一个上下文交互。
  • 开放主机服务(Open Host Service):定义一种协议来让其他上下文来对本上下文进行访问。
  • 发布语言(Published Language):通常与OHS一起使用,用于定义开放主机的协议。
  • 大泥球(Big Ball of Mud):混杂在一起的上下文关系,边界不清晰。
  • 另谋他路(SeparateWay):两个完全没有任何联系的上下文。

子域类型

核心域

核心域是一款软件的所能获得的竞争优势的根本所在。所以在核心的建模和开发主要投入大量的时间和人力。

通用域

通用域是许多大型软件系统都有的子域。通用域例如像电子邮件和短信发送、OSS、MQ等。

支撑域

系统中的其他域被称为支撑域。支撑域的主要作用就是有助于支撑核心域的业务。比如:用户的注册等。

分析模型(从领域建模角度分析需求)

DDD分析建模主要有两种方法可以使用:用例分析法、四色建模法、事件风暴、领域驱动建模。

用例分析法

通过对需求进行分析构建出用例图如下所示(举例子不一定正确):

四色建模法

这里列一下标准的四色建模法(https://www.infoq.cn/article/xh-four-color-modeling/),其实还是需要多联系才行。

时标型(Moment-Interval)对象:具有可追溯性的记录运营或管理数据的时刻或时段对象,用红色表示 -> 操作

PPT(Party/Place/Thing)对象:代表参与到流程中的参与方/地点/物,用绿色表示 -> 名词

角色(Role)对象:在时标型对象与 PPT 对象(通常是参与方)之间参与的角色,用黄色表示 -> 操作角色

描述(Description)对象:对 PPT 对象的一种补充描述,用蓝色表示 -> 表述备注

领域建模并不是没有方法,而是选择太多,有用例法、四色建模、领域驱动建模、事件风暴等,人有一个特点是喜欢找最简单、最易用的方法,每个方法都有自己的特点,并没有好坏优劣之分,只有适不适合。听到一个方法就去尝试,尝试到一半就放弃,一种种方法尝试,最终就会迷失在方法选择上。

识别模型(主要构成)


构造模型(找到聚合根)


细化模型(反复优化)

对于DDD而言领域建模完成后,我们就需要对照模型进行开发,在开发之间我们需要知道领域战略设计中的几种架构风格。

  1. 名词做类、动词为方法,生成渐层次模型
  2. 将渐层次模型归纳划分,做更抽象的

DDD四层架构

DDD四层架构是一个松散分层架构(任意上层可以调用下层,但是下层不能调用上层),DDD四层架构的含义如下:

  1. 用户接口层:用户界面层,或者表现层,负责向用户显示解释用户命令(类似于传统三层架构中的Controller层);
  2. 应用层:定义软件要完成的任务,并且指挥协调领域对象进行不同的操作。该层不包含业务领域知识。这层和传统三层架构中不同点在于MVC中所有的业务逻辑都在Service层,但是DDD四层结构中将业务逻辑下层到领域层,应用层只负责定义方法,然后调用领域层进行处理。应用服务可以用于控制持久化事务和安全认证等。应用服务本身并不处理业务逻辑,但它确却是领域模型的直接客户。
  3. 领域层:领域层是系统的核心,负责表达业务概念,业务状态信息以及业务规则。即包含了该领域(问题域)所有复杂的业务知识抽象和规则定义。该层主要精力要放在领域对象分析上,可以从实体,值对象,聚合(聚合根),领域服务,领域事件,仓储,工厂等方面入手。
  4. 基础设施层:该层主要有两方面内容,一是为领域模型提供持久化机制,当软件需要持久化能力时候才需要进行规划;一是对其他层提供通用的技术支持能力,如消息通信,通用工具,配置等的实现;

如下是DDD四层架构图:

依赖倒置原则(DIP)

依赖倒置原则:我们要依赖不变或稳定的元素(类、模块或层),抽象不应该依赖于细节,细节应该依赖于抽象。依赖倒置原则可以改进分层架构,即底层服务应该依赖于高层组件所提供的接口。

?采用了依赖注入方式后,其实可以发现事实上已经没有分层概念了。无论高层还是底层,实际只依赖于抽象,整个分层好像被推平了,这就引入下一个架构六边形架构。

六边形架构

六边形架构是Alistair Cockburn在2005年提出的,在这种架构中,不同的客户通过“平等”的方式与系统交互。在《实现领域驱动设计》一书中,作者将六边形架构应用到领域驱动设计的实现,六边形的内部代表了application和domain层。外部代表应用的驱动逻辑、基础设施或其他应用。内部通过端口和外部系统通信,端口代表了一定协议,以API呈现。个人理解其实就是变成内层、适配层&外部资源,内层是应用层和领域层;适配层是之前的接口层和基础设施层;外部资源就是对外接口、缓存、MQ、数据库等等。六边形架构图如下所示:

?下面是对六边型架构的一个落地实践示例:

?

四层架构、DIP、六边形架构可以参考:

https://www.jianshu.com/p/c405aa19a049

http://it.hzqiuxm.com/ddd%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E6%88%98%E7%95%A5%E7%AF%87%EF%BC%884%EF%BC%89/#DDD-2

CQRS

在DDD设计思路中,DDD 通过领域对象之间的交互实现业务逻辑与流程,并通过分层的方式将业务逻辑剥离出来,单独进行维护,从而控制业务本身的复杂度。但是作为一个业务系统,查询的相关功能也是不可或缺的。在实现各式各样的查询功能时,往往会发现很难用领域模型来实现。假设在用户需要一个订单相关信息的查询功能,展现的是查询结果的列表。列表中的数据来自于订单、商品、品类、送货地址等多个领域对象中的某几个字段。这样的场景如果还是通过领域对象来封装就显的很麻烦,其次与领域知识也没有太紧密的关系。所以命令查询职责分离的设计架构(CQRS)是可以很好的解决上述的问题。

CQRS将系统分为两类操作:命令(command)、查询(Query)。命令则是对会引起数据发生变化操作的总称,即我们常说的新增,更新,删除这些操作,都是命令。而查询则和字面意思一样,即不会对数据产生变化的操作,只是按照某些条件查找数据。CQRS 的核心思想是将这两类不同的操作进行分离,然后在两个独立的服务中实现。这种独立服务可以是两个不同的应用或者同一个应用中不同的包进行隔离。同时理论上命令和查询的数据源也是不同的(实现读写分离)。

当然读写分离模式,肯定会遇到事务的问题,事务问题主要的包含两种情况:

  1. 当 command 端完成数据更新后,需要通过事件的形式通知 query 端系统,这就存在着一定的时间差,如果你的业务对于数据完整的实时性非常高,那么可能 CQRS 不一定适合你。
  2. 其次一个 command 触发的事件在 query 端可能需要更新数个数据模型,而这也是有可能失败的。一旦更新失败那么数据就会长时间的处于不一致状态,需要外部的介入。

所以从事务的角度来看 CQRS,你需要面对的是问题从根本来说是个最终一致性的问题。对于团队处理这种最终一致性问题需要有对应的方案。

CQRS架构如下所示:

?领域对象

了解了战略设计后,我们主要做具体的实施,具体实施时我们需要了解实体、值对象和聚合这几个领域对象。

实体&值对象

我们先看一下他们的定义:

实体:许多对象不是由它们的属性来定义,而是通过一系列的连续性(continuity)和标识(identity)来从根本上定义的。只要一个对象在生命周期中能够保持连续性,并且独立于它的属性(即使这些属性对系统用户非常重要),那它就是一个实体。

值对象:当你只关心某个对象的属性时,该对象便可作为一个值对象。为其添加有意义的属性,并赋予它相应的行为。我们需要将值对象看成不变对象,不要给它任何身份标识,还应该尽量避免像实体对象一样的复杂性。

对于实体Entity,实体核心是用唯一的标识符来定义,而不是通过属性来定义。即即使属性完全相同也可能是两个不同的对象。同时实体本身有状态的,实体又演进的生命周期,实体本身会体现出相关的业务行为,业务行为会实体属性或状态造成影响和改变。

如果从值对象本身无状态,不可变,并且不分配具体的标识层面来看。那么值对象可以仅仅理解为实际的Entity对象的一个属性结合而已。该值对象附属在一个实际的实体对象上面。值对象本身不存在一个独立的生命周期,也一般不会产生独立的行为。

对于实体和值对象详细说明可以参考:https://www.jianshu.com/p/da51d16dbdc4

聚合&聚合根

聚合是业务和逻辑紧密关联的实体和值对象组合而成,聚合是数据修改和持久化的基本单元,一个聚合对应一个数据的持久化;同时将选择一个实体作为每个聚合的根,并仅允许外部对象持有对聚合根的引用。作为一个整体来定义聚合的属性和不变量,并把其执行责任赋予聚合根或指定的框架机制。

https://www.cnblogs.com/laozhang-is-phi/p/9916785.html

最小化集成

在所有的DDD项目中,通常存在多个限界上下文,这意味着我们需要找到合适的方法对这些上下文进行集成。当模型概念从上游上下文流入下游上下文中时, 尽量使用值对象来表示这些概念。这样的好处是可以达到最小化集成,即可以最小化下游模型中用于管理职责的属性数目。使用不变的值对象使得我们做更少的职责假设。

贫血模型&充血模型

贫血模型:指使用的领域对象中只有setter和getter方法(POJO),所有的业务逻辑都不包含在领域对象中而是放在业务逻辑层。贫血模型中领域对象只有属性没有丰富的操作,使用时需要单独的Dao层配合使用,风格比较面向过程。

充血模型:将大多数业务逻辑和持久化放在领域对象中,业务逻辑只是完成对业务逻辑的封装、事务和权限等的处理。充血模型更加倾向于面向对象的设计风格(可以参考:https://www.jianshu.com/p/fae3da337ebc)。

模块&领域服务&工厂

模块(Module)是DDD中明确提到的一种控制限界上下文的手段,在我们的工程中,一般尽量用一个模块来表示一个领域的限界上下文。一般的工程中包的组织方式为{com.公司名.组织架构.业务.上下文.*},这样的组织结构能够明确的将一个上下文限定在包的内部。
领域服务:领域中的服务表示一个无状态的操作,它用于实现特定于某个领域的任务。
工厂:在DDD中有可能存在复杂对象的创建,如果使用对象本身进行创建有可能会破坏单一责任原则,所以需要工厂进行对象创建。

TML 或超文本标记语言 允许 Web 用户使用元素、标签和属性创建和构造部分、段落和链接。然而,值得注意的是,HTML 不能被视为一种编程语言,因为它不能创建动态功能。

HTML有很多用例,即:

  1. 网页开发。开发人员使用 HTML 代码来设计浏览器如何显示网页元素,例如文本、超链接和媒体文件。
  2. 互联网导航。由于 HTML 被大量用于嵌入超链接,因此用户可以轻松地在相关页面和网站之间导航和插入链接。
  3. 网络文档。HTML 使组织和格式化文档成为可能,类似于 Microsoft Word。
  4. 还值得注意的是,HTML 现在被视为官方 Web 标准。万维网联盟 (W3C)维护和开发 HTML 规范,同时提供定期更新。

本文将介绍 HTML 的基础知识,包括它的工作原理、优缺点以及它与 CSS 和 JavaScript 的关系。

什么是 HTML?

HTML(代表超文本标记语言)是构成大多数网页和在线应用程序的计算机语言。超文本是用于引用其他文本片段的文本,而标记语言是告诉 Web 服务器文档的样式和结构的一系列标记。

HTML 是如何工作的

在国内的网站上找了一圈,这应该是介绍历史最细致的,长按保存手机里翻译

html文件

平均每个网站包含几个不同的信息 HTML 页面。例如,主页、关于页面和联系页面都将具有单独的 HTML 文件。

HTML 文档是以 .html 或 .htm 扩展名结尾的文件。Web 浏览器读取 HTML 文件并呈现其内容,以便互联网用户可以查看它。

html元素的三个部分

所有 HTML 页面都有一系列 HTML 元素,由一组标签和属性组成。HTML 元素是网页的构建块。标签告诉 Web 浏览器元素在哪里开始和结束,而属性描述元素的特征。

元素的三个主要部分是:

  • 开始标签 - 用于说明元素开始生效的位置。标签用左尖括号和右尖括号包裹。例如,使用开始标签 <p> 创建一个段落。
  • 内容——这是其他用户看到的输出。
  • 结束标签 - 与开始标签相同,但在元素名称前有一个正斜杠。例如,</p> 结束一个段落。

这三个部分的组合将创建一个 HTML 元素:

<p>这是在HTML中添加段落的方法。</p>

HTML 元素的另一个关键部分是它的属性,它有两个部分——名称和属性值。名称标识用户想要添加的附加信息,并且属性值给出进一步的说明。

例如,添加紫色和 font-family verdana 的样式元素将如下所示:

< p style="color:purple;font-family:verdana" >这是在HTML中添加段落的方法。< /p >

另一个属性,HTML 类,对于开发和编程来说是最重要的。class 属性添加了可以作用于具有相同类值的不同元素的样式信息。 例如,我们将对标题 <h1> 和段落 <p> 使用相同的样式。样式包括背景颜色、文本颜色、边框、边距和填充,在 .important 类下。要在 <h1> 和 <p> 之间实现相同的样式,请在每个开始标记后添加 class=”important”:

<html>
<head>
<style>
.important {
  background-color: blue;
  color: white;
  border: 2px solid black;
  margin: 2px;
  padding: 2px;
}
</style>
</head>
<body>
<h1 class="important">This is a heading</h1>
<p class="important">This is a paragraph.</p>
</body>
</html>

大多数元素都有一个开始标签和一个结束标签,但有些元素不需要结束标签即可工作,例如空元素。这些元素不使用结束标签,因为它们没有内容:

< img src="/" alt="图像" >

这个图像标签有两个属性——一个src属性,图像路径,和一个alt属性,描述性文本。但是,它没有内容,也没有结束标签。

最后,每个 HTML 文档都必须以 <!DOCTYPE> 声明开头,以告知 Web 浏览器文档类型。使用 HTML5,doctype HTML public 声明将是:

< !DOCTYPE html >

最常用的 HTML 标签和 HTML 元素

目前,有 142 个 HTML 标签可以用于创建各种元素。尽管现代浏览器不再支持其中一些标签,但学习所有可用的不同元素仍然是有益的。

第二节将讨论最常用的 HTML 标签和两个主要元素——块级元素和内联元素。

块级元素

块级元素占据页面的整个宽度。它总是在文档中开始一个新行。例如,标题元素将位于与段落元素不同的行中。

每个 HTML 页面都使用这三个标签:

  • <html>标签是定义整个 HTML 文档的根元素。
  • <head> 标签保存页面标题和字符集等元信息。
  • <body>标签包含了页面上出现的所有内容。
<html>
  <head>
    <!-- META INFORMATION -->  
  </head>
  <body>
    <!-- PAGE CONTENT -->
  </body>
</html>

其他流行的块级标签包括:

  • 标题标签 - 这些范围从 <h1> 到 <h6>,其中标题 h1 的大小最大,当它们向上移动到 h6 时变得越来越小。
  • 段落标签——全部使用 <p> 标签括起来。
  • 列表标签——有不同的变体。<ol> 标签用于有序列表,<ul> 用于无序列表。然后,使用 <li> 标记将各个列表项括起来。

内联元素

内联元素格式化块级元素的内部内容,例如添加链接和强调的字符串。内联元素最常用于在不破坏内容流的情况下格式化文本。

例如,一个 <strong> 标签会以粗体呈现一个元素,而 <em> 标签会以斜体显示它。超链接也是使用 <a> 标记和 href 属性来指示链接目标的内联元素:

<a href="https://www.icodingdeu.com/" >点我!</a> 

HTML 演变——HTML 和 HTML5 有什么区别?

HTML 的第一个版本由 18 个标签组成。从那时起,每个新版本都带有添加到标记中的新标签和属性。迄今为止,该语言最重大的升级是 2014 年引入的 HTML5。

HTML 和 HTML5的主要区别在于HTML5 支持新类型的表单控件。HTML5 还引入了几个语义标签,可以清楚地描述内容,例如 <article>、<header> 和 <footer>。

HTML 的优点和缺点

就像任何其他计算机语言一样,HTML 有其优点和局限性。以下是 HTML 的优缺点:

优点:

  • 初学者友好: HTML 具有干净且一致的标记,以及较浅的学习曲线。
  • 支持领域广:该语言被广泛使用,拥有大量资源和庞大的社区。
  • 无障碍:它是开源的并且完全免费。HTML 在所有 Web 浏览器中本机运行。
  • 灵活的:HTML很容易与PHPNode.js等后端语言集成。

就像任何其他计算机语言一样,HTML 有其优点和局限性。以下是 HTML 的优缺点:

缺点:

  • 静止的 该语言主要用于静态网页。对于动态功能,您可能需要使用 JavaScript 或 PHP 等后端语言。
  • 单独的 HTML 页面 用户必须为 HTML 创建单独的网页,即使元素相同。
  • 浏览器兼容性 一些浏览器采用新特性的速度很慢。有时较旧的浏览器并不总是呈现较新的标签。

HTML、CSS 和 Javascript 是如何相关的

HTML 用于添加文本元素并创建内容结构。然而,仅仅建立一个专业的和完全响应的网站是不够的。因此,HTML 需要借助层级样式表 (CSS)和JavaScript来创建绝大多数网站内容。

  • CSS 负责样式,例如背景、颜色、布局、间距和动画。
  • JavaScript 添加了动态功能,例如滑块、弹出窗口和照片库。这三种语言是前端开发的基础。

结论

HTML 是 Internet 上的主要标记语言。每个 HTML 页面都有一系列创建网页或应用程序内容结构的元素。

HTML 是一种对初学者友好的语言,有很多支持,主要用于静态网站页面。HTML 与用于样式的 CSS 和用于功能的 JavaScript 一起使用效果最好。

我们还向您展示了一些在线教学课程,它们将有助于提高您的 HTML 知识或提供对 HTML 的基本理解。

如果您有任何其他喜欢的资源来学习 HTML,请在评论部分告诉我们。

<html>
	<head> 
		标题 ---此处放置标题、导航、登录等内容
		<!此处放置标题、导航、登录等内容--->
	</head>
	<body> 
		<!此处放置页面主要内容--->
		<! :空格
		<: 小于号
		>: 大于号
		": 引号--->
		<p>第一段 世界大势,合久必分,分久必合。</p>
		<hr/> <!表示单行横线显示--->
		<br/> <!表示换行--->
		<h1> hello world, html is easy</h1>
		<h2> hello world, html is easy</h2>
		<h3> hello world, html is easy</h3>
		<h4> hello world, html is easy</h4>
		<h5> hello world, html is easy</h5>
		<h6> hello world, html is easy</h6>
		<p>普通字体</p>
		<b>粗体</b> <i>斜体</i> <del>本文字已被删除,请忽略</del>
		
		<p> hello     world</p>  <!段落标记--->
		<a href="http://www.baidu.com" target="_self"> 点击进入百度</a>
		<br/>
		<img src="http://mysite.com/mypic.png" alt="网站作者照片">
		<h3> 普通无边框表格:</h3>
		<table>
		<tr>
			<td>row 1 cell 1</td> <td>row 1 cell 2</td> <td>row 1 cell 3</td>
		</tr>
		<tr>
			<td>row 2 cell 1</td> <td>row 2 cell 2</td> <td>row 2 cell 3</td>
		</tr>
		</table>
		
		<h3>带表头,有边框,有跨列单元:</h3>
		<table border="1">
		<tr>
			<th>head1</th> <th>head2</th> <th>head3</th>
		</tr>
		<tr>
			<td>row 1 cell 1</td> <td>row 1 cell 2</td> <td>row 1 cell 3</td>
		</tr>
		<tr>
			<td>row 2 cell 1</td> <td>row 2 cell 2</td> <td>row 2 cell 3</td>
		</tr>
		</table>
		
		<h3>三种列表的表达方式:</h3>
		<table cellpadding="2" cellspacing="2">
		<tr>
			<td>
				<ul><li>python</li> <li>c++</li> <li>java</li> <li>golang</li></ul>
			</td>
			<td>
				<ol><li>python</li> <li>c++</li> <li>java</li> <li>golang</li></ol>
			</td>
		</tr>
		</table>
		<dl>
			<dt>CPU</dt><dd>处理器</dd>
			<dt>MEM</dt><dd>内存</dd>
		</dl>
		
		<body bgcolor="#FF0000">
		<body bgcolor="RGB(255,0,0)">
		<body bgcolor="RED">
		
		<p>视频</p>
		<object
			classid="clsid:d27sfsfstqwetsasasdfsdfs"
			codebase="http://fpdownload.macromedia.com/pub/shckwave/cabs/flash/swflash.cab">
			<embed src="flashfile.swf" width="300" height="200"></embed>
		</object>
		<br/>
		
		<p>音频</p>
		<audio controls="crontrols">
			<source src="sample_song.mp3" type="audio/mp3" />
		</audio>
		
		<br/>
		<p>视频</p>
		<video controls="controls"/>
			<source src="sample_video.mp4" type="video/mp4">
		</video>
		
	    <p>html表单---文本输入</p>
		<table>
			<tr>
				<td>用户名:</td>
				<td><input type="text" name="name"></td>
				<td>密码:</td>
				<td><input type="password" name="pass"></td>
			</tr>
			<tr>
			<tdcolspan="4"> <textarea name="comment" rows="5" cols="60"> </textarea></td>
			</tr>
		</table>
		
		<table>
			<tr>
				<td>性别:</td>
				<td>用户名:</td>
				<td>男性<input type="radio" checked='checked' name="sex" value="male" /></td>
				<td>女性<input type="radio" checked='checked' value="female" /></td>
			</tr>
			<tr>
			<tdcolspan="4"> <textarea name="comment" rows="5" cols="60"> </textarea></td>
			</tr>
		</table>
		
	</body>

</html>