SysExtension 프레임워크를 사용하여 Dynamics AX 2012에서 인스턴스화할 하위 클래스 찾기
게시됨: 2025년 2월 16일 오전 12시 25분 49초 UTC
이 문서에서는 Dynamics AX 2012 및 Dynamics 365 for Operations의 잘 알려지지 않은 SysExtension 프레임워크를 사용하여 특성 장식을 기반으로 하위 클래스를 인스턴스화하고, 이를 통해 처리 클래스 계층 구조를 쉽게 확장 가능한 방식으로 설계하는 방법을 설명합니다.
Using the SysExtension Framework to Find Out Which Subclass to Instantiate in Dynamics AX 2012
이 게시물의 정보는 Dynamics AX 2012 R3에 기반합니다. 다른 버전에는 유효할 수도 있고 그렇지 않을 수도 있습니다. (업데이트: 이 기사의 정보는 Dynamics 365 for Operations에도 유효하다는 것을 확인할 수 있습니다.)
Dynamics AX에서 처리 클래스를 구현할 때 종종 각 하위 클래스가 열거형 값에 해당하거나 다른 데이터 결합이 있는 클래스 계층을 만드는 데 직면하게 됩니다. 그런 다음 고전적인 디자인은 슈퍼 클래스에 생성 메서드를 두는 것입니다. 이 메서드에는 입력에 따라 인스턴스화할 클래스를 결정하는 스위치가 있습니다.
이 방법은 원칙적으로 잘 작동하지만, 가능한 입력이 여러 개 있는 경우(열거형의 여러 요소 또는 입력이 여러 가지 다른 값의 조합인 경우)에는 유지 관리가 번거롭고 오류가 발생하기 쉬우며, 새로운 하위 클래스를 추가하거나 입력에 따라 사용할 하위 클래스를 변경하는 경우 해당 생성자 메서드를 수정해야 한다는 단점이 항상 있습니다.
다행히도 훨씬 더 우아하지만 불행히도 훨씬 덜 알려진 방법이 있습니다. 바로 SysExtension 프레임워크를 사용하는 것입니다.
이 프레임워크는 하위 클래스를 데코레이트하는 데 사용할 수 있는 속성을 활용하여 시스템이 어떤 하위 클래스를 사용하여 무엇을 처리해야 하는지 파악할 수 있도록 합니다. 여전히 생성자 메서드가 필요하지만 올바르게 수행하면 새 하위 클래스를 추가할 때 수정할 필요가 없습니다.
상상의 예를 살펴보고 InventTrans 테이블을 기반으로 어떤 종류의 처리를 하는 계층을 구현한다고 가정해 보겠습니다. 어떤 처리를 할지는 레코드의 StatusReceipt와 StatusIssue에 따라 달라지며, 레코드가 SalesLine, PurchLine 또는 둘 다 아닌지 여부에 따라 달라집니다. 이미 여러분은 많은 다른 조합을 보고 있습니다.
그러면 지금은 소수의 조합만 처리하면 되지만, 시간이 지나면서 점점 더 많은 조합을 처리해야 한다는 것도 알고 있다고 가정해 보겠습니다.
비교적 간단하게 설명하자면, 지금은 ReservPhysical 또는 ReservOrdered의 StatusIssue를 가진 SalesLine과 관련된 레코드만 처리하면 되고, 다른 모든 조합은 지금은 무시해도 됩니다. 하지만 나중에 이들도 처리해야 하기 때문에 쉽게 확장할 수 있는 방식으로 코드를 설계하고 싶을 것입니다.
현재 귀하의 계층 구조는 다음과 같습니다.
- 내 프로세서
- 내 프로세서 판매
- 내 프로세서_판매_예약주문됨
- 내 프로세서_판매_예약물리적
- 내 프로세서 판매
이제, ModuleInventPurchSales와 StatusIssue 열거형을 기반으로 하위 클래스를 인스턴스화하는 슈퍼 클래스의 메서드를 쉽게 구현할 수 있습니다. 하지만 그러면 하위 클래스를 추가할 때마다 슈퍼 클래스를 수정해야 하며, 이는 객체 지향 프로그래밍에서 상속의 개념이 아닙니다. 결국, 새 배치 작업을 추가할 때마다 RunBaseBatch 또는 SysOperationServiceBase를 수정할 필요가 없습니다.
대신 SysExtension 프레임워크를 사용할 수 있습니다. 그러려면 SysAttribute를 확장해야 하는 다른 클래스를 추가해야 합니다. 이 클래스는 처리 클래스를 장식할 수 있는 속성으로 사용됩니다.
이 클래스는 SysOperation 구현을 위한 데이터 계약 클래스를 만드는 방법과 매우 유사합니다. 즉, 값을 가져오고 설정하기 위한 일부 데이터 멤버와 parm 메서드가 있습니다.
우리의 경우 ClassDeclaration은 다음과 같습니다.
{
ModuleInventPurchSales module;
StatusIssue statusIssue;
StatusReceipt statusReceipt
}
모든 데이터 멤버를 인스턴스화하기 위해 new() 메서드를 만들어야 합니다. 원한다면 일부 또는 모든 기본값을 제공할 수 있지만 저는 그렇게 하지 않았습니다.
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
;
super();
module = _module;
statusIssue = _statusIssue;
statusReceipt = _statusReceipt;
}
그리고 각 데이터 멤버에 대한 parm 메서드도 구현해야 하지만, 여기서는 그 방법을 알고 계시리라 생각하여 생략했습니다. 그렇지 않다면 연습 삼아 생각해 봅시다 ;-)
이제 속성 클래스를 사용하여 각 처리 클래스를 장식할 수 있습니다. 예를 들어 클래스 선언은 다음과 같습니다.
StatusIssue::None,
StatusReceipt::None)]
class MyProcessor_Sales extends MyProcessor
{
}
[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
StatusIssue::ReservOrdered,
StatusReceipt::None)]
class MyProcessor_Sales_ReservOrdered extends MyProcessor_Sales
{
}
[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
StatusIssue::ReservPhysical,
StatusReceipt::None)]
class MyProcessor_Sales_ReservPhysical extends MyProcessor_Sales
{
}
물론 클래스의 이름을 원하는 대로 지을 수 있지만, 여기서 중요한 부분은 클래스가 수행하는 처리 유형에 해당하는 속성으로 클래스를 장식하는 것입니다. (하지만 Dynamics AX에는 클래스 계층에 대한 명명 규칙이 있으며, 가능하다면 항상 이를 따르는 것이 좋습니다.)
이제 각 클래스가 어떤 종류의 처리를 수행하는지 식별할 수 있도록 클래스를 꾸몄으므로 SysExtension 프레임워크를 활용하여 필요에 따라 하위 클래스의 객체를 인스턴스화할 수 있습니다.
슈퍼 클래스(MyProcessor)에 다음과 같이 생성 메서드를 추가할 수 있습니다.
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
MyProcessor ret;
MyProcessorSystemAttribute attribute;
;
attribute = new MyProcessorSystemAttribute( _module,
_statusIssue,
_statusReceipt);
ret = SysExtensionAppClassFactory::getClassFromSysAttribute(classStr(MyProcessor), attribute);
if (!ret)
{
// no class found
// here you could throw an error, instantiate a default
// processor instead, or just do nothing, up to you
}
return ret;
}
정말 흥미로운 부분 - 그리고 이 전체 게시물의 진짜 객체(말장난은 용서하세요) - 는 SysExtensionAppClassFactory 클래스의 getClassFromSysAttribute() 메서드입니다. 이 메서드가 하는 일은 계층 구조의 슈퍼 클래스 이름(그리고 이 슈퍼 클래스는 계층 구조의 맨 위에 있을 필요가 없습니다. 이 클래스를 확장하는 클래스만 적격하다는 것을 의미합니다)과 속성 객체를 허용한다는 것입니다.
그런 다음 지정된 슈퍼 클래스를 확장 하고 해당 속성으로 장식된 클래스의 객체를 반환합니다.
물론 원하는 만큼의 검증이나 논리를 생성 메서드에 추가할 수 있지만, 여기서 중요한 요점은 일단 구현하면 이 메서드를 다시 수정할 필요가 없다는 것입니다. 계층 구조에 하위 클래스를 추가할 수 있으며 적절하게 장식하는 한 생성 메서드는 작성 당시에는 존재하지 않았더라도 찾을 것입니다.
성능은 어떨까요? 솔직히 벤치마킹을 시도해 본 적은 없지만, 제 직감으로는 클래식 스위치 문 디자인보다 성능이 떨어질 것 같습니다. 하지만 Dynamics AX에서 가장 많은 성능 문제가 데이터베이스 액세스로 인해 발생한다는 점을 고려하면 그다지 걱정할 필요는 없을 것 같습니다.
물론, 수천 개의 객체를 빠르게 생성해야 하는 것을 구현하는 경우 더 자세히 조사하고 싶을 수 있지만, 긴 처리를 위해 단일 객체를 인스턴스화하는 고전적인 사례에서는 중요하지 않을 것입니다.또한 문제 해결 팁(다음 문단)을 고려하면 SysExtension 프레임워크는 캐싱에 의존하는 것으로 보이므로 실행 중인 시스템에서는 성능이 크게 저하될 것이라고 생각하지 않습니다.문제 해결: 하위 클래스가 올바르게 데코레이션되었다고 확신하더라도 construct 메서드가 하위 클래스를 찾지 못하는 경우 캐싱 문제일 수 있습니다.클라이언트와 서버 모두에서 캐시를 지워보세요.실제로 AOS를 다시 시작할 필요는 없지만 마지막 수단일 수 있습니다.