OPAMC架构先容

打印 上一主题 下一主题

主题 644|帖子 644|积分 1932

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
         ;对象聚集:
         [objects (mutable-set)])
        ;添加对象:
        (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 [w 30]
               [coordinator (make-coordinator)])
        (define/public (draw dc)
          (set-for-each
           objects
           (lambda (id/o)
             (let ([p/transform
                    (send coordinator get-property-value transform
                          (send coordinator get-property id/o transform))])
               (when p/transform
                 (let ([pos (transform-position p/transform)]
                       [ro (transform-rotation p/transform)]
                       [sc (transform-scale p/transform)])
                   (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 ([id/o (create-guid-string)])
        (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 ([ps (properties id/o)])
        (when ps
          (set-add! (properties id/o) id/p))))
    ;移除属性:
    (define/public (remove-property id/o id/p)
      (let ([ps (properties id/o)])
        (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 ([os (objects id/p)])
        (when os
          (set-add! os id/o))))
    ;移除对象:
    (define/public (remove-object id/p id/o)
      (let ([os (objects id/p)])
        (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 ([values (get-values type)]
            [id/p (create-guid-string)])
        (hash-set! values id/p value)
        id/p))
    ;销毁属性值:
    (define/public (destroy-value type id/p)
      (let ([values (get-values type)])
        (unless (hash-empty? values)
          (hash-remove! values id/p))))
    ;取得属性值:
    (define/public (get-value type id/p)
      (let ([values (get-values type)])
        (if values
            (hash-ref values id/p (lambda () #f))
            #f)))
    ;设置属性值:
    (define/public (set-value type id/p value)
      (let ([values (get-values type)])
        (hash-set! values id/p value)))
    ;查找属性值:
    ;如果找到,返回属性id,否则返回#f.
    (define/public (find-value type value)
      (let ([values (get-values type)]
            [id/p #f])
        (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 ([a (get-action type)])
        (when a
          (send a get-objects))))
    ;添加对象:
    (define/public (add-object type id/o)
      (let ([a (get-action type)])
        (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
     [manager/o (make-object-manager)]
     [manager/p (make-property-manager)]
     [manager/pv (make-property-value-manager)]
     [manager/a (make-action-manager)])
    ;对象相关方法:-----------------------------------------
    ;创建对象:
    (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 ([id/p (send manager/pv find-value type value)])
        (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 ([id/p #f])
        (for ([id (send manager/o properties id/o)])
          #: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 ([id/v (send manager/pv find-value type value)]
            [n (set-count (send manager/p objects id/p))])
        (cond
          ;给定属性值已经存在,将该存在的属性设置给对象:
          [id/v
           (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 ([id/v (send manager/pv add-value type value)])
             (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 ([as (get-actions)])
        (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企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

没腿的鸟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表