【问题标题】:How to Update child class when parent class changes in Enterprise ArchitectEnterprise Architect中父类更改时如何更新子类
【发布时间】:2014-06-17 11:32:10
【问题描述】:

我想在 Enterprise Architect (10.0 版) 中制作一个实现继承的类图。我添加了一个抽象类,然后创建了 3 个实现抽象类的类。
现在,如果我对抽象类进行一些更改,子类不会改变。 (例如给抽象类增加一个方法,但是子类没有这个方法)。
当父类改变时如何更新(或刷新)子类?

【问题讨论】:

    标签: oop abstract-class enterprise-architect


    【解决方案1】:

    选择班级并按Ctrl + Shift + o 刷新。但是,这不会执行完全刷新,因此您需要删除旧版本的操作等,但 EA 将显示覆盖方法对话框。

    【讨论】:

      【解决方案2】:

      您可以使用我的插件EA-Matic 来执行此操作。

      EA-Matic 捕获 Enterprise Architect 中的插件事件并将它们转发到内置脚本环境。

      这允许创建具有完整插件功能的脚本,同步覆盖只是可能的应用程序之一。

      我编写的用于演示加载项的示例脚本之一就是这样做的:Automatically synchronize overrides in Enterprise Architect with EA-Matic

      此示例脚本使用事件EA_OnContextItemChanged 来存储所选操作的覆盖

      'Event Called when a new element is selected in the context. We use this operation to keep the id of the selected operation and a list of its overrides
      'Because now is the only moment we are able to find it's overrides. Once changed we cannot find the overrides anymore because then they already
      'have a different signature
      function EA_OnContextItemChanged(GUID, ot)
          'we only want to do something when the selected element is an operation
          if ot = otMethod then
              'get the model
              dim model
              set model = getEAAddingFrameworkModel()
              'get the operation
              dim operation
              set operation = model.getOperationByGUID(GUID)
              'remember the operationID
              operationID = operation.id
              'remember the overrides
              set overrides = getOverrides(operation, model)
              Repository.WriteOutput "EA-Matic", overrides.Count & " overrides found for: " & operation.name,0
          end if
      end function
      

      EA_OnNotifyContextItemModified 修改覆盖,以防发生变化。

      'Event called when an element is changed. Unfortunately EA doesn't call it for an operation, only for the owner so we have to work with that.
      function EA_OnNotifyContextItemModified(GUID, ot)
          'we only want to do something when the selected element is an operation
          if ot = otElement then
              'get the operation
              'Here we use the EA API object directly as most set methods are not implemented in EA Addin Framework
              dim wrappedOperation
              set wrappedOperation = Repository.GetMethodByID(operationID)
              dim modifiedElement
              set modifiedElement = Repository.GetElementByGuid(GUID)
              if not wrappedOperation is Nothing and not modifiedElement is Nothing then
                  'check to be sure we have the same operation
                  if modifiedElement.ElementID = wrappedOperation.ParentID AND overrides.Count > 0 then
                      dim synchronizeYes
                      synchronizeYes = MsgBox("Found " & overrides.Count & " override(s) for operation "& modifiedElement.Name & "." & wrappedOperation.Name & vbNewLine & "Synchronize?" _
                                              ,vbYesNo or vbQuestion or vbDefaultButton1, "Synchronize overrides?")
                      if synchronizeYes = vbYes then
                          synchronizeOverrides wrappedOperation
                          'log to output
      
                          Repository.WriteOutput "EA-Matic", "Operation: " & wrappedOperation.name &" synchronized" ,0
                      end if
                      'reset operationID to avoid doing it all again
                      operationID = 0
                  end if
              end if
          end if
      end function
      

      在 OnContextItemChanged 中,它首先通过查询从模型中选择具有相同签名的所有操作来获取覆盖。

      'gets the overrides of the given operation by first getting all operations with the same signature and then checking if they are owned by a descendant
      function getOverrides(operation, model)
          'first get all operations with the exact same signature
          dim overrideQuery
          overrideQuery = "select distinct op2.OperationID from (((t_operation op " & _
                          "inner join t_operation op2 on op2.[Name] = op.name) "& _
                          "left join t_operationparams opp on op.OperationID = opp.OperationID) "& _
                          "left join t_operationparams opp2 on opp2.OperationID = op2.OperationID) "& _
                          "where op.OperationID = "& operation.id &" "& _
                          "and op2.ea_guid <> op.ea_guid "& _
                          "and (op2.TYPE = op.Type OR (op2.TYPE is null AND op.Type is null)) "& _
                          "and (op2.Classifier = op.Classifier OR (op2.Classifier is null AND op.Classifier is null)) "& _
                          "and (opp.Name = opp2.Name OR (opp.Name is null AND opp2.Name is null)) "& _
                          "and (opp.TYPE = opp2.TYPE OR (opp.TYPE is null AND opp2.Type is null)) "& _
                          "and (opp.DEFAULT = opp2.DEFAULT OR (opp.DEFAULT is null AND opp2.DEFAULT is null)) "& _
                          "and (opp.Kind = opp2.Kind OR (opp.Kind is null AND opp2.Kind is null)) "& _
                          "and (opp.Classifier = opp2.Classifier OR (opp.Classifier is null AND opp2.Classifier is null)) "
          dim candidateOverrides
          set candidateOverrides = model.ToArrayList(model.getOperationsByQuery(overrideQuery))
          'then get the descendants of the owner
          dim descendants
          dim descendant
          'first find all elements that either inherit from the owner or realize it
          dim owner
          set owner = model.toObject(operation.owner)
          set descendants = getDescendants(owner, model)
          'then filter the candidates to only those of the descendants
          'loop operations backwards
          dim i
          for i = candidateOverrides.Count -1 to 0 step -1
              dim found
              found = false
              for each descendant in descendants
                  if descendant.id = model.toObject(candidateOverrides(i).owner).id then
                      'owner is a descendant, operation can stay
                      found = true
                      exit for
                  end if
              next
              'remove operation from non descendants
              if not found then
                  candidateOverrides.RemoveAt(i)
              end if
          next
          set getOverrides = candidateOverrides
      end function
      

      然后我们将其所有操作所有者的后代(递归)过滤为仅由后代拥有的操作。

      'gets all descendant of an element. That is all subclasses and classes that Realize the element.
      'Works recursively to get them all.
      function getDescendants(element, model)
          dim descendants
          dim getdescendantsQuery
          getdescendantsQuery = "select c.Start_Object_ID as Object_ID from (t_object o " _
                          & "inner join t_connector c on c.End_Object_ID = o.Object_ID) " _
                          & "where "_
                          & "(c.[Connector_Type] like 'Generali_ation' "_
                          & "or c.[Connector_Type] like 'Reali_ation' )"_
                          & "and o.Object_ID = " & element.id
          set descendants = model.toArrayList(model.getElementWrappersByQuery(getdescendantsQuery))
          'get the descendants descendants as well
          dim descendant
          dim descendantsChildren
          for each descendant in descendants
              if IsEmpty(descendantsChildren) then
                  set descendantsChildren = getDescendants(descendant, model)
              else
                  descendantsChildren.AddRange(getDescendants(descendant, model))
              end if
          next
          'add the descendantsChildren to the descendants
          if not IsEmpty(descendantsChildren) then
              if  descendantsChildren.Count > 0 then
                  descendants.AddRange(descendantsChildren)
              end if
          end if
          set getDescendants = descendants
      end function
      

      最后它使用以下函数同步操作

      'Synchronizes the operation with it's overrides
      function synchronizeOverrides(wrappedOperation)
          dim override
          for each override in overrides
              dim wrappedOverride
              set wrappedOverride = override.WrappedOperation
              'synchronize the operation with the override
              synchronizeOperation wrappedOperation, wrappedOverride
              'tell EA something might have changed
              Repository.AdviseElementChange wrappedOverride.ParentID
          next
      end function
      
      'Synchronizes the operation with the given override
      function synchronizeOperation(wrappedOperation, wrappedOverride)
          dim update
          update = false
          'check name
          if wrappedOverride.Name <> wrappedOperation.Name then
              wrappedOverride.Name = wrappedOperation.Name
              update = true
          end if
          'check return type
          if wrappedOverride.ReturnType <> wrappedOperation.ReturnType then
              wrappedOverride.ReturnType = wrappedOperation.ReturnType
              update = true
          end if
          'check return classifier
          if wrappedOverride.ReturnType <> wrappedOperation.ReturnType then
              wrappedOverride.ReturnType = wrappedOperation.ReturnType
              update = true
          end if
          if update then
              wrappedOverride.Update
          end if
          'check parameters
          synchronizeParameters wrappedOperation, wrappedOverride
      end function
      
      'Synchronizes the parameters of the given operatin with that of the overrride
      function synchronizeParameters(wrappedOperation, wrappedOverride)
          'first make sure they both have the same number of parameters
          if wrappedOverride.Parameters.Count < wrappedOperation.Parameters.Count then
              'add parameters as required
              dim i
              for i = 0 to wrappedOperation.Parameters.Count - wrappedOverride.Parameters.Count -1
                  dim newParameter
                  set newParameter = wrappedOverride.Parameters.AddNew("parameter" & i,"")
                  newParameter.Update
              next
              wrappedOverride.Parameters.Refresh
          elseif wrappedOverride.Parameters.Count > wrappedOperation.Parameters.Count then
              'remove parameters as required
              for i = wrappedOverride.Parameters.Count -1 to wrappedOperation.Parameters.Count step -1
                  wrappedOverride.Parameters.DeleteAt i,false
              next
              wrappedOverride.Parameters.Refresh
          end if
          'make parameters equal
          dim wrappedParameter
          dim overriddenParameter
          dim j
          for j = 0 to wrappedOperation.Parameters.Count -1
              dim parameterUpdated
              parameterUpdated = false
              set wrappedParameter = wrappedOperation.Parameters.GetAt(j)
              set overriddenParameter = wrappedOverride.Parameters.GetAt(j)
              'name
              if overriddenParameter.Name <> wrappedParameter.Name then
                  overriddenParameter.Name = wrappedParameter.Name
                  parameterUpdated = true
              end if
              'type
              if overriddenParameter.Type <> wrappedParameter.Type then
                  overriddenParameter.Type = wrappedParameter.Type
                  parameterUpdated = true
              end if
              'default
              if overriddenParameter.Default <> wrappedParameter.Default then
                  overriddenParameter.Default = wrappedParameter.Default
                  parameterUpdated = true
              end if
              'kind
              if overriddenParameter.Kind <> wrappedParameter.Kind then
                  overriddenParameter.Kind = wrappedParameter.Kind
                  parameterUpdated = true
              end if
              'classifier
              if overriddenParameter.ClassifierID <> wrappedParameter.ClassifierID then
                  overriddenParameter.ClassifierID = wrappedParameter.ClassifierID
                  parameterUpdated = true
              end if
              'update the parameter if it was changed
              if parameterUpdated then
                  overriddenParameter.Update
              end if
          next
      end function
      

      【讨论】:

      • 请在此处解释您的插件。
      • @kleopatra 我根据您的要求在回答中添加了(很多)更多细节。
      【解决方案3】:

      当您告诉 EA 覆盖或实现基类或接口中的操作时,它会在子类中创建该操作的副本。这个副本没有引用原来的基类/接口,后续的变化也没有体现在child中。

      如果您为接口绘制实现并选择不覆盖任何操作,EA 将按您的预期为它们生成代码,但它不会为抽象类执行此操作 - 即使子类是叶子。

      您始终可以修改代码生成模板(工具 - 源代码生成模板)。第一次了解它们有点棘手,但你很快就会掌握它的窍门。

      【讨论】:

      • 没有办法更新子类? (删除然后重绘除外)
      猜你喜欢
      • 2015-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-28
      • 2016-02-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多