Smalltalk/Pharo中是否无预定义dynamic 2D container?需自行实现吗?
完全懂你的纠结!Pharo的核心哲学就是优先复用现有组件而非从零构建,所以自己写完自定义2D容器后总觉得哪里不对,这种感觉太正常了——其实你大概率是没挖到Pharo里可以直接组合或者现成的替代方案,我给你梳理几个方向:
基于原生集合嵌套封装
Pharo里的Array和OrderedCollection本身就支持嵌套,你完全可以基于它们来封装动态2D容器的行为,不用从头实现底层存储。比如如果需要行列均匀的矩阵,就用Array嵌套,然后给封装类加自动扩容的访问方法;如果需要每行长度可变的结构,就用OrderedCollection嵌套,实现动态添加行列的逻辑。举个简单的封装示例:Object subclass: #Dynamic2DContainer instanceVariableNames: 'rows' classVariableNames: '' package: 'MyContainers' Dynamic2DContainer >> initialize super initialize. rows := OrderedCollection new. Dynamic2DContainer >> at: rowIndex at: colIndex rowIndex > rows size ifTrue: [ ^ nil ]. ^ (rows at: rowIndex) at: colIndex ifAbsent: [ nil ] Dynamic2DContainer >> at: rowIndex at: colIndex put: aValue "自动扩展行列以支持指定坐标" [ rows size < rowIndex ] whileTrue: [ rows add: OrderedCollection new ]. targetRow := rows at: rowIndex. [ targetRow size < colIndex ] whileTrue: [ targetRow add: nil ]. targetRow at: colIndex put: aValue这个实现完全复用了
OrderedCollection的动态特性,符合Pharo"组合优先"的理念。社区现成的2D容器库
Pharo的Catalog里有不少成熟的第三方包已经实现了动态2D容器/矩阵功能,比如Matrix相关的库,不仅支持动态扩容,还自带很多便捷的操作方法(比如行列遍历、转置等),直接搜索就能找到,完全不用自己造轮子。利用Traits扩展原生集合
如果你不想单独封装类,还可以用Pharo的Trait特性,给Array或者OrderedCollection添加2D访问的行为,这样原生集合就能直接当成动态2D容器用。比如定义一个TDynamic2DTrait,实现at:at:、at:at:put:等方法,然后让需要的集合类use这个Trait即可。
总的来说,Pharo里很少需要从头构建容器,更多是给现有集合添加行为或者组合现有集合来满足需求,这样既符合它的核心理念,也能减少重复代码。
内容的提问来源于stack exchange,提问作者The Fool

