对象组成

计算机科学中,对象组成对象聚集是将对象数据类型组合到更复杂的方法的紧密相关方法。 In conversation the distinction between composition and aggregation is often ignored. Common kinds of compositions are objects used in object-oriented programming , tagged unions , sets , sequences , and various graph structures. Object compositions relate to, but are not the same as, data structures.

对象组成是指信息的逻辑或概念结构,而不是用于表示信息的实现或物理数据结构。例如,序列集合有所不同,因为(除其他事项)组成的项目的顺序对前者而言至关重要,但在后者方面不重要。 Data structures such as arrays , linked lists , hash tables , and many others can be used to implement either of them. Perhaps confusingly, some of the same terms are used for both data structures and composites.例如,“二进制树”可以指的是:作为数据结构,它是访问线性序列的一种手段,并且树在树中的实际位置是无关紧要的(可以内部重新安排树,但是一个人喜欢,但是without changing its meaning). However, as an object composition, the positions are relevant, and changing them would change the meaning (as for example in cladograms ).

编程技术

Object-oriented programming is based on objects to encapsulate data and behavior. It uses two main techniques for assembling and composing functionality into more complex ones, sub-typing and object composition.对象组成是关于将对象组合在复合对像中,同时,通过使用定义明确的界面而无需可见的内部界面来确保每个对象的封装。 In this regard, object composition differs from data structures, which do not enforce encapsulation.

Object composition may also be about a group of multiple related objects, such as a set or a sequence of objects. Delegation may enrich composition by forwarding requests or calls made to the enclosing composite object to one of its internal components.

在基于键入的编程语言中,可以将类型分为复合和非复合类型,并且可以将组合视为类型之间的关系:复合类型的对象(例如, CAR具有“其他类型的对象”( eg wheel ).当复合对象包含相同类型的几个子对象时,它们可能会分配给特定角色,通常以名称或数字区分。 For example, a Point object might contain 3 numbers, each representing distance along a different axis, such as 'x', 'y', and 'z'. The study of part-whole relationships in general, is mereology .

构图必须与亚型区分开,这是将细节添加到一般数据类型中以创建更具体的数据类型的过程。 For instance, cars may be a specific type of vehicle: car is a vehicle .子类型没有描述不同对象之间的关系,而是说类型的对像是另一种类型的对象。 The study of such relationships is ontology .

在基于原型的编程语言(例如JavaScript)中,对象可以在其实例化时从原型对像中动态继承行为。组成必须与原型区分开:新实例化对象继承其原型的组成,但它本身可以自行组成。

Composite objects may be represented in storage by co-locating the composed objects, by co-locating references, or in many other ways.复合对像中的项目可以称为属性字段成员属性或其他名称,以及所得组成为复合类型存储记录结构元组用户定义的类型(UDT) 。 For details, see the aggregation section below.

UML modeling technique

A bycicle class represented in UML, with three properties: saddle, wheels and parts, the two last having a multiplicity indicating several objects
Object composition using UML properties to compose objects

In UML modeling, objects can be conceptually composed, independently of the implementation with a programming language. There are four ways of composing objects in UML: property, association, aggregation and composition:

  • A property represents an attribute of the class.
  • 协会代表相关类实例之间的语义关系。协会的成员端对应于关联类的属性。
  • 聚合是一种建模,该关联模拟了聚合(整个)与一组相关组件(部分)之间的部分/整个关系。
  • 一种构图,也称为复合聚合,是一种聚集,该聚合建模了复合材料(整体)和一组独家拥有的部分之间的零件/整体关系。

聚合及其组件之间的关系是弱的“ has-a”关系:组件可能是几个聚集体的一部分,可以通过其他对象访问而无需通过聚集体,并且可能比聚合对象保持不足。组件对象的状态仍然构成聚合对象的一部分。

复合及其部分之间的关​​系是一种牢固的“ has-a”关系:复合对象唯一的“对组成对象的存在和存储的责任”,组成的对象最多可以是一个复合物的一部分,而”如果删除了复合对象,则将其所有部分实例删除。因此,在UML中,组成的含义比通常的对象组成更狭窄。

Association between several bicycles each having one owner; Composition of a bicycle with frame parts which make the bicycle; and aggregation of a bicycle with its wheels, which exist without the bicycle
关联,组成和聚集的UML表示法

图形符号表示:

  • 该属性是封闭类的框中的打字元素,
  • 关联是相关类之间的平整线,
  • 聚集是骨料侧和实线侧的未填充钻石,
  • 组合物作为复合材料侧面的钻石和实线。

聚合

聚合不同于普通构图,因为它并不意味着所有权。在组成中,当拥有对像被破坏时,包含的对像也是如此。总体而言,这不一定是正确的。例如,大学拥有各个部门(例如化学),每个系都有许多教授。如果大学关闭,部门将不再存在,但是这些部门的教授将继续存在。因此,大学可以看作是部门的组成,而部门的教授汇总。此外,一位教授可以在一个以上的部门工作,但是一个系不能成为一所大学的一部分。

通常实现构图,以使对象包含另一个对象。例如,在C ++中:

class Professor;  // Defined elsewhere
class Department {
 public:
  Department(const std::string& title): title_(title) {}
 private:
  // Aggregation: |Professors| may outlive the |Department|.
  std::vector<std::weak_ptr<Professor>> members_;
  const std::string title_;
};
class University {
 public:
  University() = default;
 private:
  // Composition: |Department|s exist only as long as the faculty exists.
  std::vector<Department> faculty_ = {
      Department("chemistry"),
      Department("physics"),
      Department("arts"),
  };
};

汇总,该对像只能包含指向对象的参考或指针(并且对其不承担终身责任)。

有时,当普通组成和聚集之间的区别不重要时,聚集被称为组成。

以上代码将转换为以下UML类图:

com的聚合

com的聚合

在Microsoft的组件对像模型中,聚合意味着对象的导出,好像它是其所有者一样,它拥有的另一个对象的一个​​或几个接口。正式地,这与组成封装更相似,而不是聚集。但是,无需通过调用自有对象的接口来实现导出的接口,而是导出了自有对象的接口。拥有的对象负责确保从中继承的这些接口的方法 iunknown实际上调用了所有者的相应方法。这是为了确保所有者的参考计数是正确的,并且所有者的所有接口都可以通过导出的接口访问,而自有对象的其他(私有)接口无法访问。

特殊形式

遏制

用于存储复合数据类型的几个实例的组成称为遏制。此类容器的示例是数组关联阵列二进制树链接列表

UML中,遏制以0 ..*或1 ..*表示,表明复合对象由组合类的一个未知数的实例组成。

递归成分

物体可以递归地组成,然后将其类型称为递归类型。示例包括各种树木dag图形。树上的每个节点可以是分支或叶子。换句话说,每个节点是一棵树,同时它属于另一棵树。

在UML中,递归组成是用与本身的缔合,聚集或组成的。

复合模式

复合设计模式是基于复合类型的面向对象的设计,该设计结合了递归组成和遏制,以实现复杂的零件整体层次结构。

C中的复合类型

这是c中成分的一个示例。

struct Person
{
  int age;
  char name[20];
  enum {job_seeking, professional, non_professional, retired, student} employment;
};

在此示例中,将原始(非合并)类型INTEnum {Job_seeking,Profession,non_profersional,退休,学生}和复合阵列类型char []合并以形成复合结构的。然后,每个人的结构都具有“年龄,名称和就业类型”。

各种语言的构图时间表

C将记录称为结构或结构;诸如JavaSmallTalkC ++面向对象的语言通常将其记录隐藏在对象中(实例); ML家族中的语言只会称他们为记录。 COBOL是第一个直接支持记录的广泛编程语言Algol 68从Cobol那里获得了它, Pascal或多或少地从Algol 68中获得了它。CommonLISP提供结构和类(后者通过COMMON LISP对象系统)。

1959年 - COBOL
      01  customer-record.
        03  customer-number     pic 9(8) comp.
        03  customer-name.
          05  given-names       pic x(15).
          05  initial-2         pic x.
          05  surname           pic x(15).
        03  customer-address.
          05  street.
            07  street-name     pic x(15).
              09  house-number  pic 999 comp.
          05  city              pic x(10).
          05  country-code      pic x(3).
          05  postcode          pic x(8).
        03  amount-owing        pic 9(8) comp.
1960年 - 阿尔戈尔60

阵列是Algol 60中唯一的复合数据类型

1964年 - PL/I
dcl 1 newtypet based (P);
 2 (a, b, c) fixed bin(31),
 2 (i, j, k) float,
 2 r ptr;
allocate newtypet;
1968年 - 阿尔戈尔68
int max = 99;
mode newtypet = [0..9] [0..max]struct (
 long real a, b, c, short int i, j, k, ref real r
);
newtypet newarrayt = (1, 2, 3, 4, 5, 6, heap real := 7)

例如,链接列表可能被声明为:

mode node = union (real, int, compl, string),
 list = struct (node val, ref list next);

对于Algol 68,只有类型名称出现在平等的左侧,最值得注意的是,构造是从左到右读取的,并且可以读取,而无需考虑优先级。

1970年 - 帕斯卡(Pascal)
type
 a = array [1..10] of integer;
 b = record
  a, b, c: real;
  i, j, k: integer;
 end;
1972年 - K&R C
#define max 99
struct newtypet {
  double a, b, c;
  float r;
  short i, j, k;
} newarrayt[10] [max + 1];
1977年 - Fortran 77

Fortran 77具有数组,但缺乏任何正式的记录/结构定义。通常,复合结构是使用等价共同陈述建立的:

       CHARACTER NAME*32, ADDR*32, PHONE*16
       REAL OWING
       COMMON /CUST/NAME, ADDR, PHONE, OWING
1983 - ADA
type Cust is
 record
  Name  : Name_Type;
  Addr  : Addr_Type;
  Phone : Phone_Type;
  Owing : Integer range 1..999999;
 end record;

ADA 95通过标记类型(相当于C ++类)带来了OOP概念,ADA 2012通过通过范围的合同增加了对替代验证的支持。

1983 - C ++
const int max = 99;
class {
  public:
  double a, b, c;
  float &r;
  short i, j, k;
}newtypet[10] [max + 1];
1991 - Python
max = 99
class NewTypeT:
    def __init__(self):
        self.a = self.b = self.c = 0
        self.i = self.j = self.k = 0.0
# Initialise an example array of this class.
newarrayt = [[NewTypeT() for i in range(max + 1)] for j in range(10)]
1992 - Fortran 90

阵列和字符串从Fortran 77继承,并引入了一个新的保留词:类型

type newtypet
 double precision a, b, c
 integer*2 i, j, k
* No pointer type REF REAL R
 end type
type (newtypet) t(10, 100)

Fortran 90更新了,包括Fortran IV的概念称为Namelist。

INTEGER :: jan = 1, feb = 2, mar = 3, apr = 4
NAMELIST / week / jan, feb, mar, apr
1994年 - ANSI COMMON LISP

普通LISP提供结构,ANSI常见的LISP标准添加了关闭类别。

(defclass some-class ()
  ((f :type float)
   (i :type integer)
   (a :type (array integer (10)))))

有关C/C ++组成的更多详细信息,请参见复合类型

也可以看看