【実務・中級編】【上級プロ】クラスモジュールとファクトリーパターンの導入:複雑なアセンブリ合致パターンを拡張性高くオブジェクト指向で構築するリファクタリング – SolidWorks VBA解析バイブル

スポンサーリンク

なぜ、あなたのアセンブリ自動化マクロは「怪獣」と化すのか?

SolidWorks APIを利用したアセンブリ構築の自動化。最初は「マクロの記録」から始まり、数枚のプレートとボルトを配置して合致(Mate)を付ける程度の簡単なスクリプトだったはずです。

しかし、対応する製品バリエーションが増え、条件分岐(`If…Else`)が肥大化し、入れ子のループが重なり合った結果——気付けば1,000行を超える単一の標準モジュールが出来上がっていませんか?

  • 「ボルトの長さが変わっただけで合致がエラーで弾かれる」
  • 「新しいパーツ構造を追加しようとしたら、どこを修正すればいいか分からず全体が壊れた」
  • 「処理の途中でSolidWorksが沈黙し、タスクマネージャーから強制終了するしかない」

手続き型スクリプトの延長線上で構築された巨大なマクロは、保守不可能な「レガシーの怪獣」です。

本稿では、この負の連鎖を断ち切るために、SolidWorks VBAにクラスモジュールとファクトリーパターン(Factory Pattern)を導入する極限のリファクタリング手法を解説します。

設計意図(Design Intent)をオブジェクト指向へと昇華させ、バグの挟み込む隙すらない堅牢な自動化ライブラリを構築しましょう。

—

アーキテクチャの変革:手続き型からオブジェクト指向へ

アセンブリ自動化において最もスパゲッティ化しやすい原因は、「パーツの配置」と「合致条件の選択・適用」および「エラー判定」が密結合していることにあります。

この構造を破棄し、役割(関心事)を明確に分離します。

[呼び出し側: Controller / Main]
│
▼
[ MateFactory ] ── (生成) ──► [ IAssemblyMateStrategy ] (Interface)
│
┌──────────────┴──────────────┐
▼ ▼
[ CoincidentMateStrategy ] [ ConcentricMateStrategy ]
(一致合致) (同心円合致)

アーキテクチャ構成要素

1. `IAssemblyMateStrategy`(インターフェース)

  • すべての合致パターンが満たすべき契約(メソッドシグネチャ)を定義。

2. 具象ストラテジークラス(`CoincidentMateStrategy`, `ConcentricMateStrategy` 等)

  • 個別の合致タイプ(一致、同心円、距離など)に応じた選択処理・API呼出・エラーハンドリングを閉じた世界(カプセル化)で実行。

3. `MateFactory`(ファクトリークラス)

  • 要求された合致タイプに応じた適切なストラテジーオブジェクトを生成・返却。

4. `AssemblyAutomator`(メイン制御)

  • モデルの非表示化(描画停止)などのパフォーマンス最適化、ライフサイクル管理、ファクトリーを通じた処理の委譲を担当。

この設計により、新しい合致タイプや特殊な組み込みルールを追加する際も、既存のロジックに一切手を加えることなく、新しいクラスを1つ追加するだけで拡張が可能になります(開閉原則:Open/Closed Principle の達成)。

—

プロダクションコード実装

以下の構成でVBAプロジェクトを構築します。コードをコピーして各モジュールに配置してください。

  • Class Modules:
  • `IAssemblyMateStrategy`
  • `CoincidentMateStrategy`
  • `ConcentricMateStrategy`
  • `MateFactory`
  • Standard Modules:
  • `modMain`

1. `IAssemblyMateStrategy` (Class Module)

VBAでポリモーフィズムを実現するための抽象インターフェースです。

Option Explicit

‘ ==============================================================================
‘ Interface: IAssemblyMateStrategy
‘ 概要: すべての合致定義ストラテジーが実装すべき共通インターフェース
‘ ==============================================================================

”’

”’ 指定された2つのエンティティ(面、軸、点等)に対して合致を定義します。
”’

”’ SolidWorks Application オブジェクト ”’ 対象のアセンブリドキュメント ”’ 1つ目の要素の選択パス (例: “Component1-1@Assy/Face1”) ”’ 2つ目の要素の選択パス (例: “Component2-1@Assy/Face2”) ”’ 反転フラグ (True: アライメント反転) ”’ 合致生成が成功した場合は True
Public Function CreateMate( _
ByVal swApp As SldWorks.SldWorks, _
ByVal swAssy As SldWorks.AssemblyDoc, _
ByVal firstEntityPath As String, _
ByVal secondEntityPath As String, _
ByVal flipAlignment As Boolean _
) As Boolean
End Function

—

2. `CoincidentMateStrategy` (Class Module)

一致合致(Coincident Mate)を構築する具象クラスです。

Option Explicit

‘ ==============================================================================
‘ Class: CoincidentMateStrategy
‘ 概要: 一致合致(Coincident Mate)の適用と選択状態の制御を行う
‘ ==============================================================================
Implements IAssemblyMateStrategy

Private Function IAssemblyMateStrategy_CreateMate( _
ByVal swApp As SldWorks.SldWorks, _
ByVal swAssy As SldWorks.AssemblyDoc, _
ByVal firstEntityPath As String, _
ByVal secondEntityPath As String, _
ByVal flipAlignment As Boolean _
) As Boolean

Dim swModel As SldWorks.ModelDoc2
Set swModel = swAssy

‘ 1. 選択のクリア(堅牢性の担保)
swModel.ClearSelection2 True

‘ 2. エンティティの精密選択
‘ NOTE: Mark 1 と Mark 2 を明示的に分けて選択キューに追加する
Dim boolStatus As Boolean
boolStatus = swModel.Extension.SelectByID2(firstEntityPath, “FACE”, 0, 0, 0, True, 1, Nothing, 0)
If Not boolStatus Then
Debug.Print “[ERROR] 1つ目の要素選択に失敗: ” & firstEntityPath
IAssemblyMateStrategy_CreateMate = False
Exit Function
End If

boolStatus = swModel.Extension.SelectByID2(secondEntityPath, “FACE”, 0, 0, 0, True, 1, Nothing, 0)
If Not boolStatus Then
Debug.Print “[ERROR] 2つ目の要素選択に失敗: ” & secondEntityPath
swModel.ClearSelection2 True
IAssemblyMateStrategy_CreateMate = False
Exit Function
End If

‘ 3. 合致の生成 (AddMate5 を使用)
‘ swMateCOINCIDENT = 0, Align: swMateAlignALIGNED = 0, swMateAlignANTI_ALIGNED = 1
Dim alignOption As Long
alignOption = IIf(flipAlignment, swMateAlignType_e.swMateAlignANTI_ALIGNED, swMateAlignType_e.swMateAlignALIGNED)

Dim mateError As Long
Dim swMate As SldWorks.Mate2
Set swMate = swAssy.AddMate5( _
swMateType_e.swMateCOINCIDENT, _
alignOption, _
False, _
0, 0, 0, 0, 0, 0, 0, 0, _
False, False, 0, mateError)

If swMate Is Nothing Or mateError <> swMateError_e.swMateErrorNone Then
Debug.Print “[ERROR] 一致合致の生成に失敗。エラーコード: ” & mateError
IAssemblyMateStrategy_CreateMate = False
Else
IAssemblyMateStrategy_CreateMate = True
End If

‘ 後始末
swModel.ClearSelection2 True
End Function

—

3. `ConcentricMateStrategy` (Class Module)

同心円合致(Concentric Mate)を構築する具象クラスです。

Option Explicit

‘ ==============================================================================
‘ Class: ConcentricMateStrategy
‘ 概要: 同心円合致(Concentric Mate)の適用ロジック
‘ ==============================================================================
Implements IAssemblyMateStrategy

Private Function IAssemblyMateStrategy_CreateMate( _
ByVal swApp As SldWorks.SldWorks, _
ByVal swAssy As SldWorks.AssemblyDoc, _
ByVal firstEntityPath As String, _
ByVal secondEntityPath As String, _
ByVal flipAlignment As Boolean _
) As Boolean

Dim swModel As SldWorks.ModelDoc2
Set swModel = swAssy

swModel.ClearSelection2 True

‘ 円筒面や軸を選択する(Type指定を “FACE” または “EDGE” に可変対応させる堅牢性)
Dim boolStatus As Boolean
boolStatus = swModel.Extension.SelectByID2(firstEntityPath, “FACE”, 0, 0, 0, True, 1, Nothing, 0)
If Not boolStatus Then
‘ FACEで取れない場合はEDGEを試行するフォールバック処理
boolStatus = swModel.Extension.SelectByID2(firstEntityPath, “EDGE”, 0, 0, 0, True, 1, Nothing, 0)
End If

If Not boolStatus Then
Debug.Print “[ERROR] 同心円ターゲット1の選択失敗: ” & firstEntityPath
IAssemblyMateStrategy_CreateMate = False
Exit Function
End If

boolStatus = swModel.Extension.SelectByID2(secondEntityPath, “FACE”, 0, 0, 0, True, 1, Nothing, 0)
If Not boolStatus Then
boolStatus = swModel.Extension.SelectByID2(secondEntityPath, “EDGE”, 0, 0, 0, True, 1, Nothing, 0)
End If

If Not boolStatus Then
Debug.Print “[ERROR] 同心円ターゲット2の選択失敗: ” & secondEntityPath
swModel.ClearSelection2 True
IAssemblyMateStrategy_CreateMate = False
Exit Function
End If

‘ 同心円合致実行
Dim alignOption As Long
alignOption = IIf(flipAlignment, swMateAlignType_e.swMateAlignANTI_ALIGNED, swMateAlignType_e.swMateAlignALIGNED)

Dim mateError As Long
Dim swMate As SldWorks.Mate2
Set swMate = swAssy.AddMate5( _
swMateType_e.swMateCONCENTRIC, _
alignOption, _
False, _
0, 0, 0, 0, 0, 0, 0, 0, _
False, False, 0, mateError)

IAssemblyMateStrategy_CreateMate = (Not swMate Is Nothing And mateError = swMateError_e.swMateErrorNone)
swModel.ClearSelection2 True
End Function

—

4. `MateFactory` (Class Module)

合致タイプを識別し、対応するストラテジーオブジェクトを生成するファクトリークラスです。

Option Explicit

‘ ==============================================================================
‘ Class: MateFactory
‘ 概要: 合致ストラテジーのインスタンス化を抽象化するファクトリークラス
‘ ==============================================================================

Public Enum MateTypeEnum
MateType_Coincident = 1
MateType_Concentric = 2
‘ 必要に応じて Distance, Parallel 等をここに追加
End Enum

”’

”’ 指定されたEnumに応じた合致ストラテジーを返却します。
”’

Public Function CreateStrategy(ByVal mateType As MateTypeEnum) As IAssemblyMateStrategy
Select Case mateType
Case MateTypeEnum.MateType_Coincident
Set CreateStrategy = New CoincidentMateStrategy
Case MateTypeEnum.MateType_Concentric
Set CreateStrategy = New ConcentricMateStrategy
Case Else
Err.Raise vbObjectError + 512, “MateFactory”, “未対応の合致タイプが指定されました。”
End Select
End Function

—

5. `modMain` (Standard Module)

設計されたオブジェクト群を制御し、最適化されたアセンブリ自動構築を実行するエントリーポイントです。

Option Explicit

‘ ==============================================================================
‘ Module: modMain
‘ 概要: アセンブリ自動化の実行・グラフィック制御・ライフサイクル管理
‘ ==============================================================================

Public Sub RunAssemblyAutomation()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks

Dim swModel As SldWorks.ModelDoc2
Set swModel = swApp.ActiveDoc

‘ 1. 安全装置: アクティブドキュメントがアセンブリであるかチェック
If swModel Is Nothing OrElse swModel.GetType <> swDocumentTypes_e.swDocASSEMBLY Then
MsgBox “アクティブなアセンブリドキュメントを開いてから実行してください。”, vbExclamation, “エラー”
Exit Sub
End If

Dim swAssy As SldWorks.AssemblyDoc
Set swAssy = swModel

‘ 2. パフォーマンス極限最適化(画面描画の凍結)
‘ これにより処理速度が数倍〜数十倍に跳ね上がる
Dim swModelView As SldWorks.ModelView
Set swModelView = swModel.ActiveView

‘ 描画サスペンド
swModelView.EnableGraphicsUpdate = False
swApp.SetBufferForRedraw True

On Error GoTo ErrorHandler

‘ 3. ファクトリーの生成
Dim factory As New MateFactory
Dim mateStrategy As IAssemblyMateStrategy

‘ — 実行例 1: パートAとパートBの「同心円合致」 —
Set mateStrategy = factory.CreateStrategy(MateType_Concentric)
Dim success As Boolean
success = mateStrategy.CreateMate( _
swApp, swAssy, _
“BasePart-1@MainAssembly/CylinderFace”, _
“SubPart-1@MainAssembly/HoleFace”, _
False)

If Not success Then GoTo RollbackOrSkip

‘ — 実行例 2: パートAとパートBの「一致合致」 —
Set mateStrategy = factory.CreateStrategy(MateType_Coincident)
success = mateStrategy.CreateMate( _
swApp, swAssy, _
“BasePart-1@MainAssembly/TopFace”, _
“SubPart-1@MainAssembly/BottomFace”, _
False)

If Not success Then GoTo RollbackOrSkip

MsgBox “アセンブリの合致定義が完了しました。”, vbInformation, “成功”

CleanUp:
‘ 4. 後続処理: 画面描画の再開と強制再計算
If Not swModelView Is Nothing Then swModelView.EnableGraphicsUpdate = True
swApp.SetBufferForRedraw False
swModel.ForceRebuild3 True
Exit Sub

RollbackOrSkip:
Debug.Print “[WARNING] 一部の合致処理がスキップされました。”
Resume CleanUp

ErrorHandler:
Debug.Print “[FATAL] 予期せぬエラーが発生: ” & Err.Description
Resume CleanUp
End Sub

—

現場で差がつく上級テクニック&落とし穴回避策

1. `SelectByID2` の文字列依存からの脱却(名前付け規約の徹底)

SOLIDWORKS APIで最も失敗しやすいのが `SelectByID2` による選択です。フィーチャー名や面名が変更されると、選択処理は音もなく失敗します。

  • 対策: 構成品に「命名規約(例: `MATE_FLANGE_FACE`)」を定めておき、モデル定義側で「面の名前(Face Properties)」を設定します。APIからはその固有名をピンポイントで叩く設計を徹底してください。

2. COMオブジェクトの解放と描画バッファの完全制御

VBAはガベージコレクションが甘く、COMオブジェクトがメモリ内に残存するとSolidWorksが不安定になります。

  • 処理開始時には必ず `swModelView.EnableGraphicsUpdate = False` で描画を停止し、幾何計算のみをメモリ上で完了させます。
  • 処理終了時には `SetBufferForRedraw False` と `ForceRebuild3` をセットで呼び出し、グラフィックパイプラインを解放してください。

3. PDM / 外部データベース(CSV・SQL)連携時の注意点

アセンブリを全自動生成する際、部品のパスを外部DBやCSVから読み込むケースが多く見られます。

  • SolidWorks PDMを導入している環境では、ファイルがローカルキャッシュに存在しないと `OpenDoc6` や構成品の追加(`AddComponent5`)がサイレントエラーとなります。
  • 必ず「ローカルキャッシュ取得判定」のラッパーをファクトリー呼び出しの前段に噛ませる設計にしてください。

—

まとめ:単なる「マクロ」を「開発資産」へと進化させる

「とりあえず動くスクリプト」を書く時代は終わりです。

本稿で紹介した「ファクトリーパターン × クラスモジュールによる合致ロジックのカプセル化」を導入することで、あなたのSolidWorks VBAコードは以下の特性を獲得します。

1. 極めて高い拡張性: 新しい合致ルールが必要になっても、既存ロジックを壊さずクラスを追加するだけ。
2. 圧倒的な堅牢性: エラー箇所の特定が容易で、グラフィックフリーズの発生確率を極限まで低減。
3. チーム開発への耐性: オブジェクト指向で整理されたコードは、他のエンジニアにとっても可読性が高く、保守コストを大幅に削減。

SOLID原則に基づいた美しく堅牢なアーキテクチャを構築し、社内の自動化基盤を次の次元へと引き上げてください。

タイトルとURLをコピーしました