在D365之前,一个枚举类型对应多个子类需要实例化,通常会在construct里用switch case语句根据不同的枚举值实例化不同的子类。
这种做法的问题在于,对扩展不友好,如果枚举类型增加了新的值,想扩展,即便通过CoC扩展construct方法也是很困难的事情。
D365为了实现扩展性,针对这种场景,用了Attribute,使用扩展框架进行相应子类的实例化。
假设我们用系统里已经存在的枚举类型 Gender 性别 为例,假设我们创建一个父类Person,然后男人对应的子类是Person_Male,女人对应的子类是Person_Female。
在D365之前我们通常用如下方式实例化:
1 public static Person construct(Gender _gender) 2 { 3 switch (_gender) 4 { 5 case Gender::Male: 6 return new Person_Male(); 7 case Gender::Female: 8 return new Person_Female(); 9 default: 10 throw Error(Error::wrongUseOfFunction(funcName())); 11 } 12 }
在D365中要通过扩展框架进行实例化,下面说一下步骤:
1.创建一个Attribute类
该类继承自SysAttribute,并且实现SysExtensionIAttribute,方法很简单,主要是parmCacheKey方法。
1 public class GenderAttribute extends SysAttribute implements SysExtensionIAttribute 2 { 3 Gender gender; 4 public void new(Gender _gender) 5 { 6 gender = _gender; 7 } 8 public str parmCacheKey() 9 { 10 return classStr(GenderAttribute)+';'+int2Str(enum2int(gender)); 11 } 12 public boolean useSingleton() 13 { 14 return false; 15 } 16 }
2.在子类上增加属性
1 [Gender(Gender::Male)] 2 public class Person_Male extends Person 3 { 4 public str fromWhere() 5 { 6 return "Mars"; 7 } 8 9 } 10 11 [Gender(Gender::Female)] 12 public class Person_Female extends Person 13 { 14 public str fromWhere() 15 { 16 return "Venus"; 17 } 18 19 }
3.通过框架类SysExtensionAppClassFactory实例化并调用
入参是父类的名字和相应子类的Attribute。实现的原理很简单,通过反射找到Person的两个子类Person_Male和Person_Female,然后比对参数里的属性跟子类定义里的Attribute属性哪个能匹配,哪个能匹配就用反射实例化哪个对象并返回。
至于useSingleton方法,就是是否要在某次调用中如果需要多次实例化这个类,可以考虑使用单件模式提高效率,可以用单件模式提高效率,D365是把实例化好的对象缓存在GlobalCache对象里。
1 public static void main(Args _args) 2 { 3 Person person; 4 5 person = SysExtensionAppClassFactory::getClassFromSysAttribute( 6 classStr(Person), 7 new GenderAttribute(Gender::Male)); 8 9 info (person.fromWhere()); 10 11 person = SysExtensionAppClassFactory::getClassFromSysAttribute( 12 classStr(Person), 13 new GenderAttribute(Gender::Female)); 14 15 info (person.fromWhere()); 16 }