没腿的鸟 发表于 2024-6-20 14:53:17

OPAMC架构先容

1 OPAMC的概念

        OPAMC架构泉源于ECS架构的思想,用于实现面向对象绘图,接纳Racket语言(Lisp语言的一个方言)实现。
        ECS架构(全称Entity-Component-System,即实体-组件-系统)是一种软件架构模式,主要用于游戏开发。ECS遵循组合优于继承的原则,游戏内的每一个基本单元都是一个实体,每个实体又由一个或多个组件构成,每个组件仅仅包含代表其特性的数据(即在组件中没有任何方法),系统是处置惩罚拥有一个或多个相同组件的实体聚集的工具,它只拥有行为(即在系统中没有任何数据)。实体与组件是一个一对多的关系,实体拥有怎样的本事,完全是取决于其拥有哪些组件。通过动态添加或删除组件,可以在(游戏)运行时改变实体的行为。换句话说,每个实体不是由“范例“界说的,而是由与其关联的组件界说的。组件怎样与实体相关连,取决于所使用的ECS框架怎样设计。
        ECS的规则——“组件没有函数,系统没有状态”。
        ECS架构规避了面向对象编程(OOP)中继承造成的不敷——为对象强行创建父子关系,这种非常耦合产生的各种不灵活:耦合性的改动、不充分的继承、不灵活的重用、难以决定的归类。
        OPAMC架构同样接纳组合的方式构造数据,但规避了ECS架构中实体数量及组件数量为预先设定的问题,使它们可以根据用户需求举行动态增减。
        OPAMC架构使用对象(绘图对象,O)、属性(对象属性,P)、行为(对象行为,A)、管理器(M)、调和器(C)五个概念,将绘图对象的属性接纳组合方式举行数据构造,即一切皆属性,实现面向数据编程。而在处置惩罚具体的行为、管理、调和时,接纳面向对象(OOP)举行封装。
2 OPAMC的构成



[*] O:object,对象。指绘图操尴尬刁难象,包含实体及虚体。对象包罗:图元、实体、组、模子。对组的内部成员(实体、组的引用)作为对象的属性;实体的内部成员(图元)作为对象属性;图元的多少描述布局作为对象属性。
[*] P:property,属性。指描述对象的特性的数据布局值。属性仅提供数据(数据布局值),不包含任何行为,没有函数。可以将各种属性布局分类放在差别模块内。
[*] A:action,行为。对象的行为逻辑,负责对一组(或一个)特定对象属性举行处置惩罚,实现对象属性的控制及实现对象行为操作。行为模块之间独立存在,不互相调用。
[*] M:manager,管理器,实现对象、属性、行为的创建、添加、修改、查询及删除(CRUD),分别对应通过对象管理器、属性管理器、行为管理器实现。管理器模块与对象、属性、行为模块分开设置,实现代码完全解偶。
[*] C:coordinator,调和器。为制止模块的交叉引用并使程序逻辑更清晰,通过调和器实现对象管理器、属性管理器、行为管理器之间的调和关系;实现对象、属性、行为的综合管理,它也是对外的接口(更上层程序通过调用调和器程序间接管理数据及行为,而不是直接调用各数据及管理器程序)。各管理器仅完成自己范围内的简单操作,全部交叉操作均在调和器内举行。
3 OPAMC模块划分


[*] 对象管理器模块:包含对象管理器。以对象管理器为基类,可根据需要扩展出图元对象管理器、实体对象管理器、组对象管理器三个模块。
[*] 属性数据布局模块:可按属性数据布局分类设置差别模块。
[*] 属性管理器模块。
[*] 属性值管理器模块。
[*] 行为模块:行为类模块,并以行为类为基类,根据差别行为需求派生各自行为类。
[*] 行为管理器模块。
[*] 调和器模块。
4 OPAMC文件树布局

        OPAMC架构团体作为一个单独文件夹。其下分为如下文件及文件夹构成文件树:
-opamc(OPAMC架构文件夹)
|-property(属性文件夹)
|+全部经分类的属性模块
|-action(行为文件夹)
|+全部行为的模块
|-manager(管理器文件夹)
|-object-manager.rkt(对象管理器模块)
|-property-manager.rkt(属性管理器模块)
|-property-value-manager.rkt(属性值管理器模块)
|-action-manager.rkt(行为管理器模块)
|-coordinator.rkt(调和器模块)
        由此可以看出,OPAMC架构由:一个架构,三个文件夹(属性文件夹、行为文件夹、管理器文件夹),四个管理器(对象管理器、属性管理器、属性值管理器、行为管理器),一个调和器等构成。
5 OPAMC架构整合

5.1 OPAMC架构数据



[*] 对象(objects):(hash (对象id/o . (set 属性id/p)...)
[*] 属性(properties):(hash (范例type . (hash 属性id/p . (set 对象id/o))...)...)
[*] 属性值(property-values):(hash (范例type . (hash (属性id/p . 属性值)...)...)
[*] 行为(actions):(hash (范例type . 行为id/a)...)
5.2 OPAMC操作



[*] 对象管理器(object-manager):创建对象、销毁对象;取得对象散列表;取得属性聚集;添加属性、移除属性。
[*] 属性管理器(property-manager):添加属性、删除属性;取得对象聚集;添加对象、移除对象。
[*] 属性值管理器(property-value-manager):注册属性范例;取得属性值散列表;添加属性值、销毁属性值、取得属性值、设置属性值。
[*] 行为管理器(action-manager):注册行为;取得行为散列表;取得行为;取得对象聚集;添加对象、移除对象;判定行为范例是否存在。
[*] 调和器(coordinator):调和manager/o、manager/p、manager/pv、manager/a四个管理器。创建对象、销毁对象、取得对象散列表;注册属性、添加属性、移除属性、取得属性、取得属性值、更新属性;注册行为、添加行为、取得行为散列表、取得行为。
        管理器的操作严酷控制在简单、直接范围的操作,凡是交叉判定、交叉操作均在调和器内实现。
        数据的索引:将对象、属性值、行为均分配全局唯一id值,通过id值举行索引。由于Racket语言中布局(struct)和类(class)均为一级值,因此对于用范例(type)举行索引分类的,直接用布局范例值及类范例值作为范例(type)索引值,这样既直观又简单。
6 OPAMC实现代码

6.1 属性代码示例

        全部属性均用布局范例表现,同类属性布局放在一个模块内。


[*] 属性模块示例一:
       ;transform-property.rkt;变换属性。#lang racket(provide (struct-out transform))(struct transform  (position rotation scale))
[*] 属性模块示例二:
       ;geometry-property.rkt;多少属性。#lang racket(provide (struct-out point) (struct-out line) (struct-out arc));点:(struct point (x0 y0));线段:(struct line (p0 p1));圆弧:(struct arc (pc p0 p1))
6.2 行为代码示例

        行为接纳类来描述,以便于对差别行为的封装。行为类仅包含操尴尬刁难象聚集,而且该聚集来自于action%基类,以确保行为操尴尬刁难象均针对全部对象(如果要对对象举行分类则需要另行处置惩罚)。一般每一个行为类独占一个模块。


[*] 行为基类模块示例:
       ;action.rkt;行为基类。;行为(action)负责对一组具有特定属性(property)
;的对象(object)表举行处置惩罚。;这里的“特定”是指对象应该包含全部该行为需要的属性。#lang racket(provide action%);界说行为类:;本类为基类,每个行为类都可以从这个基类继承,;从而使得行为管理器(action-manager)可以保留指向行为的引用列表。(define action%  (class object%    (super-new)    (field     ;对象聚集:     )    ;添加对象:    (define/public (add-object id/o)      (set-add! objects id/o))    ;移除对象:    (define/public (remove-object id/o)      (set-remove! objects id/o))    ;取得对象聚集:    (define/public (get-objects)      objects)    ))   
[*] 行为派生类模块示例:
       ;draw-action.rkt;绘制行为。#lang racket(require "action.rkt"         "../coordinator.rkt"         "../property/transform-property.rkt"         "../property/display-property.rkt")(provide draw-action%);界说绘制行为类:(define draw-action%  (class action%    (super-new)    (inherit-field objects)    (field            )    (define/public (draw dc)      (set-for-each       objects       (lambda (id/o)         (let (                (send coordinator get-property-value transform                      (send coordinator get-property id/o transform))])           (when p/transform             (let (                                      )               (send dc set-origin (send pos get-x) (send pos get-y))               (send dc set-scale sc sc)               (send dc set-rotation ro)               (send dc draw-rectangle                     (- w) (- w)                     (* 2 w) (* 2 w))               ))))))    ))   
6.3 管理器代码

        每个管理器分别独立设置模块。管理器模块在OPAMC架构下可以无需改变直接使用。
        包罗四个模块:对象管理器模块、属性管理器模块、属性值管理器模块、行为管理器模块。
6.3.1 对象管理器模块

   ;object-manager.rkt;对象管理器。;每个对象包含属性标识聚集。#lang racket(require "../arithmetic/guid.rkt")(provide make-object-manager);对象散列表,每一个键值对代表一个对象。其:;键为对象标识值;值为对象属性标识值聚集。(define objects (make-hash));界说对象管理器类:(define object-manager%  (class object%    (super-new)    ;创建对象:    (define/public (create-object)      (let ()        (hash-set! objects id/o (mutable-set))        id/o))    ;销毁对象:    (define/public (destroy-object id/o)      (unless (hash-empty? objects)        (hash-remove! objects id/o)))    ;取得对象散列表:    (define/public (get-objects)      objects)    ;取得属性聚集:    (define/public (properties id/o)      (hash-ref objects id/o (lambda () #f)))    ;添加属性:    (define/public (add-property id/o id/p)      (let ()        (when ps          (set-add! (properties id/o) id/p))))    ;移除属性:    (define/public (remove-property id/o id/p)      (let ()        (when ps          (set-remove! (properties id/o) id/p))))    ));创建对象管理器:(define (make-object-manager)  (new object-manager%))6.3.2 属性管理器模块

   ;property-manager.rkt;属性管理器。;每个属性包含对象标识聚集。#lang racket(provide make-property-manager);属性散列表。其中:;键为属性标识值;值为对象标识聚集。(define properties (make-hash));界说属性管理器类:(define property-manager%  (class object%    (super-new)    ;添加属性:    (define/public (add-property id/p)      (hash-set! properties id/p (mutable-set)))    ;删除属性:    ;删除属性需满足该属性没有对象需要。    (define/public (delete-property id/p)      (when (set-empty? (objects id/p))        (hash-remove! properties id/p)))    ;取得对象聚集:    (define/public (objects id/p)      (hash-ref properties id/p (lambda () #f)))    ;添加对象:    (define/public (add-object id/p id/o)      (let ()        (when os          (set-add! os id/o))))    ;移除对象:    (define/public (remove-object id/p id/o)      (let ()        (when os          (set-remove! os id/o)))      (when (set-empty? (objects id/p))        (delete-property id/p)))    ));创建属性管理器对象:(define (make-property-manager)  (new property-manager%))6.3.3 属性值管理器模块

   ;property-value-manager.rkt;属性值管理器。#lang racket(require "../arithmetic/guid.rkt")(provide make-property-value-manager);属性范例散列表,通过属性注册产生。其:;键为属性布局范例;值为属性值散列表。;属性值散列表,通过添加产生,其键为属性标识值;值为属性值。(define types (make-hash));界说属性值管理器类:(define property-value-manager%  (class object%    (super-new)    ;注册属性范例:    (define/public (regist-type type)      (hash-set! types type (make-hash)))    ;取得指定范例属性值散列表:    (define/public (get-values type)      (hash-ref types type (lambda () #f)))    ;添加属性值:    ;如果指定属性范例不存在,则注册该属性范例。    (define/public (add-value type value)      (unless (has-type? type)        (regist-type type))      (let (            )        (hash-set! values id/p value)        id/p))    ;销毁属性值:    (define/public (destroy-value type id/p)      (let ()        (unless (hash-empty? values)          (hash-remove! values id/p))))    ;取得属性值:    (define/public (get-value type id/p)      (let ()        (if values            (hash-ref values id/p (lambda () #f))            #f)))    ;设置属性值:    (define/public (set-value type id/p value)      (let ()        (hash-set! values id/p value)))    ;查找属性值:    ;如果找到,返回属性id,否则返回#f.    (define/public (find-value type value)      (let (            )        (when values          (hash-for-each           values           (lambda (k v)             (when (equal? v value)               (set! id/p k)))))        id/p))    ;判定属性是否为指定属性范例?    (define/public (is-type? type id/p)      (hash-has-key? (get-values type) id/p))    ;判定是否存在指定属性范例?    (define/public (has-type? type)      (hash-has-key? types type))    ));创建属性值管理器:(define (make-property-value-manager)  (new property-value-manager%))6.3.4 行为管理器模块

   ;action-manager.rkt;行为管理器。负责维护已注册的行为(action)。#lang racket(require "../arithmetic/guid.rkt")(provide make-action-manager);行为散列表。其:;键为行为类标识;值为行为类对象值。(define actions (make-hash));界说行为管理器类:(define action-manager%  (class object%    (super-new)    ;注册行为:    (define/public (regist-action type)      (hash-set! actions type (new type)))    ;取得行为散列表:    (define/public (get-actions)      actions)    ;取得行为:    (define/public (get-action type)      (hash-ref actions type (lambda () #f)))    ;取得行为包含的对象聚集:    (define/public (get-objects type)      (let ()        (when a          (send a get-objects))))    ;添加对象:    (define/public (add-object type id/o)      (let ()        (when a          (send a add-object id/o))))    ;移除对象:    (define/public (remove-object id/o)      (hash-for-each       actions       (lambda (k v)         (send v remove-object id/o))))    ;判定范例是否存在:    (define/public (has-type? type)      (hash-has-key? actions type))    ));创建行为管理器:(define (make-action-manager)  (new action-manager%))6.4 调和器代码

        调和器独立设置模块,实现对象管理器、属性管理器、属性值管理器、行为管理器的交叉通讯,制止模块之间的交叉引用,举行同一管理、同一对外接口。调和器模块在OPAMC架构下可以无需改变直接使用。
   ;coordinator.rkt;调和器。;负责完成对象管理器、属性管理器、属性值管理器、行为管理器之间交叉的行为,;制止模块之间的交叉引用。#lang racket(require "manager/object-manager.rkt"         "manager/property-manager.rkt"         "manager/property-value-manager.rkt"         "manager/action-manager.rkt")(provide make-coordinator);界说调和器类:(define coordinator%  (class object%    (super-new)    (field                    )    ;对象相关方法:-----------------------------------------    ;创建对象:    (define/public (create-object)      (send manager/o create-object))    ;销毁对象:    (define/public (destroy-object id/o)      (send manager/o destroy-object id/o)      (send manager/p remove-object id/o)      (send manager/a remove-object id/o))    ;取得对象散列表:    (define/public (get-objects)      (send manager/o get-objects))    ;属性相关方法:-------------------------------------------    ;注册属性:    (define/public (regist-property type)      (unless (send manager/pv has-type? type)        (send manager/pv regist-property type)))    ;添加属性:    ;如果value在属性列表中不存在,则添加。    (define/public (add-property id/o type value)      (let ()        (unless id/p          (set! id/p (send manager/pv add-value type value))          (send manager/p add-property id/p))        (send manager/o add-property id/o id/p)        (send manager/p add-object id/p id/o)))    ;移除属性:    (define/public (remove-property id/o id/p)      (send manager/o remove-property id/o id/p)      (send manager/p remove-object id/p id/o))    ;取得属性:    (define/public (get-property id/o type)      (let ()        (for ()          #:break (not (send manager/pv is-type? type id))          (set! id/p id))        id/p))    ;取得属性值:    (define/public (get-property-value type id/p)      (send manager/pv get-value type id/p))    ;更新属性:    (define/public (update-property type id/o id/p value)      (let (            )        (cond          ;给定属性值已经存在,将该存在的属性设置给对象:                     (send manager/p remove-object id/p id/o)           (send manager/p add-object id/v id/o)           (send manager/o remove-property id/o id/p)           (send manager/o add-property id/o id/v)]          ;属性仅属于一个对象,仅改变属性值:          [(= n 1)           (send manager/pv set-value type id/p value)]          ;属性属于多个对象,新创建属性给对象:          [(> n 1)           (let ()             (remove-property id/o id/p)             (send manager/p register-property id/v)             (send manager/p add-object id/v id/o)             (send manager/o add-property id/o id/p))])))    ;行为相关方法:--------------------------------------------    ;注册行为:    (define/public (regist-action type)      (unless (send manager/a has-type? type)        (send manager/a regist-action type)))    ;添加行为:    (define/public (add-action id/o type)      (send manager/a add-object type id/o))    ;取得行为散列表:    (define/public (get-actions)      (send manager/a get-actions))    ;取得行为:    (define/public (get-action type)      (let ()        (if (hash-empty? as)            #f            (hash-ref as type))))    ));创建调和器对象:(define (make-coordinator)  (new coordinator%))6.5 id标识代码

        以上的对象管理器、属性值管理器、行为管理器模块中,均出现了(require "../arithmetic/guid.rkt"),其中”arithmetic“是用来放置数学盘算模块的文件夹,其中的guid.rkt是用来生成id索引标识的函数generate-guid所在的模块文件。
        值的阐明的是,这里接纳的为随机生成的16个字符索引标识值,现实接纳的id索引标识有各种选择,好比IFC规范的GUID为是二进制长度为128位的数字标识符,UUID一般为32个字符的字符串等。
        该文件的主要内容如下:
   ;guid.rkt;生成唯一标记(GUID)。#lang racket(require racket/random)(provide generate-guid);……;作为guid的另一个选择,通过随机产生字节码:(define (generate-guid) (crypto-random-bytes 16)) ;……7 总结

        OPAMC架构是一个伸缩性很强的以面向数据编程的软件框架,其速率不如DCS,但扩展性是其重要特点。我把它用在我本人实现的面向对象绘图的软件中,目的是为了实现”一切皆属性“的思想,让绘图处置惩罚过程逻辑上高度同一。
        各人如对OPAMC架构有差别的意见或建议,接待举行批评。
以上内容用Racket语言的Scribble编辑并编译生成。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: OPAMC架构先容