5.3 基础支撑之用户与客户域

一、三户概念

三户由来

介绍下经典的三户模型,它是电信运营支持系统的基础。三户模型即客户、用户和帐户,来源于etom的模型。这三者之间的关系应该是一个相互关联但又是独立的三个实体,这种关联只是一个归属和映射的关系,而三个实体本身是相互独立的,分别是体现完全不同的几个域的信息,客户是体现了社会域的信息,用户体现了业务域的信息,帐户体现的是资金域的信息。

  1. 客户:它是个社会化的概念,一个自然人或一个法人

  2. 用户:它是客户使用运营商开发的一个产品以及基于该产品之上的增值业务时,产生的一个实体。如果说一个客户使用了多个产品,那么一个客户就会对应好几个用户(即产品)

  3. 账户:它的概念起源于金融业,只是一个客户在运营商存放资金的实体,目的是为选择的产品付费

Oinone的三户

在原三户模型中【用户】是购买关系产生的产品与客户关系的服务实例,在互联网发展中用户的概念发生了非常大的变化,【用户】概念变成了:使用者,是指使用电脑或网络服务的人,通常拥有一个用户账号,并以用户名识别。而且新概念在互联网强调用户数的大背景下已经被普遍介绍,再去强调电信行业的用户概念就会吃力不讨好。而且不管是企业应用领域和互联网领域,原用户概念都显得过于复杂和没有必要。也就有了特色的oinone的三户模型:

  1. 客户:它是个社会化的概念,一个自然人或一个法人

  2. 用户:使用者,是指使用电脑或网络服务的人,通常拥有一个用户账号,并以用户名识别

  3. 账户:它的概念起源于金融业,只是一个客户在运营商存放资金的实体,目的是为选择的产品付费

二、Oinone的客户与用户

三户模型是构建上层应用的基础支撑能力,任何业务行为都跟这里两个实体脱不了干系。以客户为中心建立商业关系与商业行为主体,以用户为中心构建一致体验与操作行为主体。在底层设计上二者相互独立并无关联,由上层应用自行作关联绑定,往往在登陆时在Session的处理逻辑中会根据【用户】去找到对应一个或多个【商业(主体)客户】,Session的实现可以参考4.1.20【框架之Session】一文。

5.3 基础支撑之用户与客户域

图5-3-1 Oinone的客户与用户

客户设计说明

  1. PamirsPartner作为商业关系与商业行为的主体,派生了两个子类PamirsCompany与PamirsPerson分别对应:公司(法人)客户、自然人客户

  2. 公司(法人)客户PamirsCompany对应多个组织部门PamirsDepartment,公司(法人)客户PamirsCompany对应多个员工PamirsEmployee

  3. 部门PamirsDepartment对应一个公司(法人)客户PamirsCompany,对应多个员工PamirsEmployee

  4. 员工PamirsEmployee对应多个部门PamirsDepartment,对应一个或多个公司(法人)客户PamirsCompany,其中有一个主的

用户设计说明

  1. PamirsUser作为一致体验与操作行为主体,本身绑定登陆账号,并且可以关联多个三方登陆账户PamirsUserThirdParty

客户与用户如何关联(举例)

例子设计:

  1. 新建demo系统的PetComany和PetEmployee,用PetEmployee去关联用户。

  2. 当用户登陆时,根据用户Id找到PetEmployee,在根据PetEmployee找到PetComany,把PetComany放到Session中去

  3. 修改PetShop模型关联一个PamirsPartner,PamirsPartner的信息从Session取。

Step1 pamirs-demo-api工程增加依赖,并且DemoModule增加对BusinessModule的依赖

<dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-business-api</artifactId>
</dependency>

图5-3-2 pamirs-demo-api工程增加依赖

在DemoModule类中通过@Module.dependencies中增加BusinessModule.MODULE_MODULE

@Module(
    dependencies = { BusinessModule.MODULE_MODULE}
)

图5-3-3 声明对BusinessModule的依赖

Step2 新建PetComany和PetEmployee,以及对应的服务

package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.business.api.model.PamirsEmployee;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.user.api.model.PamirsUser;

@Model.model(PetEmployee.MODEL_MODEL)
@Model(displayName = "宠物公司员工",labelFields = "name")
public class PetEmployee extends PamirsEmployee {
    public static final String MODEL_MODEL="demo.PetEmployee";

    @Field(displayName = "用户")
    private PamirsUser user;

}

图5-3-4 新建PetEmployee

package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.business.api.entity.PamirsCompany;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

@Model.model(PetCompany.MODEL_MODEL)
@Model(displayName = "宠物公司",labelFields = "name")
public class PetCompany extends PamirsCompany {

    public static final String MODEL_MODEL="demo.PetCompany";

    @Field.Text
    @Field(displayName = "简介")
    private String introductoin;

}

图5-3-5 新建PetComany

package pro.shushi.pamirs.demo.api.service;

import pro.shushi.pamirs.demo.api.model.PetEmployee;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;

@Fun(PetEmployeeQueryService.FUN_NAMESPACE)
public interface PetEmployeeQueryService {
    String FUN_NAMESPACE ="demo.PetEmployeeQueryService";
    @Function
    PetEmployee queryByUserId(Long userId);

}

图5-3-6 新建PetEmployee对应服务

package pro.shushi.pamirs.demo.core.service;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.demo.api.model.PetEmployee;
import pro.shushi.pamirs.demo.api.service.PetEmployeeQueryService;
import pro.shushi.pamirs.framework.connectors.data.sql.query.QueryWrapper;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;

@Fun(PetEmployeeQueryService.FUN_NAMESPACE)
@Component
public class PetEmployeeQueryServiceImpl implements PetEmployeeQueryService {

    @Override
    @Function
    public PetEmployee queryByUserId(Long userId) {
        if(userId==null){
            return null;
        }
        QueryWrapper<PetEmployee> queryWrapper = new QueryWrapper<PetEmployee>().from(PetEmployee.MODEL_MODEL).eq("user_id", userId);
        return new PetEmployee().queryOneByWrapper(queryWrapper);
    }

}

图5-3-7 新建PetEmployee对应服务

package pro.shushi.pamirs.demo.api.service;

import pro.shushi.pamirs.demo.api.model.PetCompany;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;

@Fun(PetCompanyQueryService.FUN_NAMESPACE)
public interface PetCompanyQueryService {
    String FUN_NAMESPACE ="demo.PetCompanyQueryService";
    @Function
    PetCompany queryByCode(String code);
}

图5-3-8 新建PetComany对应服务

package pro.shushi.pamirs.demo.core.service;

import org.apache.dubbo.common.utils.StringUtils;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.demo.api.model.PetCompany;
import pro.shushi.pamirs.demo.api.service.PetCompanyQueryService;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;

@Fun(PetCompanyQueryService.FUN_NAMESPACE)
@Component
public class PetCompanyQueryServiceImpl implements PetCompanyQueryService {

    @Override
    @Function
    public PetCompany queryByCode(String code) {
        if(StringUtils.isBlank(code)){
            return null;
        }
        return new PetCompany().queryByCode(code);
    }

}

图5-3-9 新建PetComany对应服务

Step3 Session中增加PamirsPartner

对DemoSession\DemoSessionApi\DemoSessionData\DemoSessionHolder进行修改,增加PetCompany getCompany()相关方法。可以参考4.1.20【框架之Session】一文。

对DemoSessionCache修改如下,增加根据userId获取employee,以及根据employee获取PetCompany

package pro.shushi.pamirs.demo.core.session;

import pro.shushi.pamirs.demo.api.model.PetCompany;
import pro.shushi.pamirs.demo.api.model.PetEmployee;
import pro.shushi.pamirs.demo.api.service.PetCompanyQueryService;
import pro.shushi.pamirs.demo.api.service.PetEmployeeQueryService;
import pro.shushi.pamirs.meta.api.CommonApiFactory;
import pro.shushi.pamirs.meta.api.session.PamirsSession;
import pro.shushi.pamirs.user.api.model.PamirsUser;
import pro.shushi.pamirs.user.api.service.UserService;

public class DemoSessionCache {
    private static final ThreadLocal<DemoSessionData> BIZ_DATA_THREAD_LOCAL = new ThreadLocal<>();
    public static PamirsUser getUser(){
        return BIZ_DATA_THREAD_LOCAL.get()==null?null:BIZ_DATA_THREAD_LOCAL.get().getUser();
    }
    public static PetCompany getCompany(){
        return BIZ_DATA_THREAD_LOCAL.get()==null?null:BIZ_DATA_THREAD_LOCAL.get().getCompany();
    }
    public static void init(){
        if(getUser()!=null){
            return ;
        }
        Long uid = PamirsSession.getUserId();
        if(uid == null){
            return;
        }
        PamirsUser user = CommonApiFactory.getApi(UserService.class).queryById(uid);
        if(user!=null){
            DemoSessionData demoSessionData = new DemoSessionData();
            demoSessionData.setUser(user);

            PetEmployee employee = CommonApiFactory.getApi(PetEmployeeQueryService.class).queryByUserId(uid);
            if(employee!=null){
                PetCompany company = CommonApiFactory.getApi(PetCompanyQueryService.class).queryByCode(employee.getCompanyCode());
                demoSessionData.setCompany(company);
            }
            BIZ_DATA_THREAD_LOCAL.set(demoSessionData);
        }
    }
    public static void clear(){
        BIZ_DATA_THREAD_LOCAL.remove();
    }
}

图5-3-10 Session中增加PamirsPartner

Step4 修改PetShop模型,以及重写PetShop的默认create方法

PetShop模型增加partner字段,修改openTime为readonly=true的配置,变成带条件readonly。scene == \'redirectUpdatePage\'表示只有再修改的时候为只读

@Field(displayName = "所属主体" )
@UxForm.FieldWidget(@UxWidget(readonly = "scene == 'redirectUpdatePage'"/* 在编辑页面只读 **/ ))
private PamirsPartner partner;

图5-3-11 修改PetShop模型

创建PetShopAction类重写PetShop模型的create方法

package pro.shushi.pamirs.demo.core.action;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.demo.api.model.PetCompany;
import pro.shushi.pamirs.demo.api.model.PetShop;
import pro.shushi.pamirs.demo.core.session.DemoSession;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.ViewTypeEnum;

@Component
@Model.model(PetShop.MODEL_MODEL)
public class PetShopAction {

    @Action.Advanced(name= FunctionConstants.create,managed = true)
    @Action(displayName = "确定",summary = "确定",bindingType = ViewTypeEnum.FORM)
    @Function(name=FunctionConstants.create)
    @Function.fun(FunctionConstants.create)
    public PetShop create(PetShop data){
        //从session中获取登陆主体信息
        PetCompany company =  DemoSession.getCompany();
        if(company!=null){
            data.setPartner(company);
        }
        data.create();
        return data;
    }

}

图5-3-12 创建PetShopAction类重写PetShop模型的create方法

Step5 增加PetEmployee和PetCompany的管理入口

DemoMenus增加@UxMenu注解申明

@UxMenu("公司管理")@UxRoute(PetCompany.MODEL_MODEL) class PetCompanyMenu{}
@UxMenu("员工管理")@UxRoute(PetEmployee.MODEL_MODEL) class PetEmployeeMenu{}

图5-3-13 用注解方式增加菜单

Step6 重启应用看效果

  1. 创建公司与员工,在创建的同时建立公司与员工,员工与用户关联

image.png

图5-3-14 创建公司与员工

image.png

图5-3-15 员工与用户关联

  1. 创建一个宠物店铺

新增oinone的宠物店铺003,但不要选择所属主体。点击确定按钮后期望效果是:会从session中自动获取admin关联的PetCompany,并填充到宠物店铺的所属主体字段中

image.png

图5-3-16 新增Oinone的宠物店铺003

image.png

图5-3-17 自动获取admin关联的PetCompany

Step7 注意事项

  1. PetEmployee 的create方法应该重写,再调用PamirsEmployeeService 的create方法

  2. PetEmployeeQueryServiceImpl的queryByUserId方法实现上也没有考虑一个用户绑定多个员工的模式。

  3. employeeType 字段默认是不展示的,但是例子中又没有重写PetEmployee 的create方法,所以这个值是空的。但这个字段为空,会导致报错。解决办法有两个

    1. 重写create,手动给employeeType赋值

    2. 自定义员工创建页面,拿到公司列表和部门列表两个字段。

5.3 基础支撑之用户与客户域 5.3 基础支撑之用户与客户域

图5-3-18 注意事项

三、客户扩展申明

按CDM的设计理念,我们不以把模型抽象到极致支撑所有业务可能性为目标,而是抽象80%通用的设计,保持模型简单可理解。我们只提供了基础模型统一数据存储,以用面向对象特性来解决多应用模型复用和数据割裂问题。

Oinone CDM是商业领域的通用模型,更是结合oinone特性提出的新工程建议

Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9318.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
史, 昂's avatar史, 昂数式管理员
Previous 2024年5月23日 am8:20
Next 2024年5月23日 am8:22

相关推荐

  • 3.5.5.1 设计器数据导出

    简介 通过调用导出接口,将设计器的设计数据与运动数据打包导出到文件中。 提供了download/export两类接口。 export 导出到OSS。导出的文件会上传到文件服务,通过返回的url下载导出文件。 请求示例: mutation { uiDesignerExportReqMutation { export( data: { module: "gemini_core", fileName: "meta", moduleBasics: true } ) { jsonUrl } } } 响应示例: { "data": { "uiDesignerExportReqMutation": { "export": { "jsonUrl": "https://xxx/meta.json" } } }, "errors": [], "extensions": {} } download 直接返回导出数据。适用于通过浏览器直接下载文件。 请求示例: mutation { uiDesignerExportReqMutation { download( data: { module: "gemini_core", fileName: "meta", moduleBasics: true } ) { jsonUrl } } } 如何构造url protocol :// hostname[:port] / path ? query=URLEncode(GraphQL) 例: http://127.0.0.1:8080/pamirs/base?query=mutation%20%7B%0A%09uiDesignerExportReqMutation%20%7B%0A%09%09download(%0A%09%09%09data%3A%20%7B%20module%3A%20%22gemini_core%22%2C%20fileName%3A%20%22meta%22%2C%20moduleBasics%3A%20true%20%7D%0A%09%09)%20%7B%0A%09%09%09jsonUrl%0A%09%09%7D%0A%09%7D%0A%7D 在浏览器中访问构造后的url,可直接下载文件 接口列表 模型设计器 指定模块导出 query { modelMetaDataExporterQuery { export/download(query: { module: "模块编码" }) { module url } } } module参数:指定导出的模块编码 url返回结果:export方式导出的文件url 页面设计器 导出页面 指定模块导出 mmutation { uiDesignerExportReqMutation { download/export( data: { module: "gemini_core", fileName: "meta", moduleBasics: false } ) { jsonUrl } } } module参数:模块编码 fileName参数:指定生成的json文件名称 moduleBasics参数:指定是否只导出模块基础数据,如果为true,只导出内置布局、模块菜单、菜单关联的动作。 如果为false,还会导出模块内的所有页面,以及页面关联的动作元数据、页面设计数据 等等。 默认值为false。 指定菜单导出 mutation { uiDesignerExportReqMutation { download/export( data: { menu: { name: "uiMenu0000000000048001" } fileName: "meta" relationViews: true } ) { jsonUrl } } } menu参数:菜单对象,指定菜单的name。只会导出该菜单及其绑定页面,不会递归查询子菜单 fileName参数:指定生成的json文件名称 relationViews参数:指定是否导出关联页面,默认为false,只导出菜单关联的页面。如果为true,还会导出该页面通过跳转动作关联的自定义页面。 指定页面导出 mutation { uiDesignerExportReqMutation { download/export( data: { view: { name: "xx_TABLE_0000000000119001" model: "ui.designer.TestUiDesigner" } fileName: "meta" relationViews: true } ) { jsonUrl } } }…

    Oinone 7天入门到精通 2024年5月23日
    2.1K00
  • 数据编码

    1. 什么是数据编码 当模型中的字段数据需要有一定的编码规定,可以在模型中设计模型或字段的数据编码。 编码预览:实时展示规则设置后的编码。 2. 编码前/后缀 编码前缀:必须以字母开头,且仅支持数字或字母,最多8个字符。 编码后缀:必须以字母开头,且仅支持数字或字母,最多8个字符。 3. 格式化日期 开关默认关闭,即数据编码中不包含日期。开关打开后,默认的日期格式为“年年年年月月日日”,也可以切换成“年年月月日日、年年月月、年年年年、年年”。 序列归零周期:与格式化日期选择有关,若选择为“年年年年月月日日”,则可选“年、月、日”,选择为“年年年年”,则只可选“年”数据编码序列会按照设置的这个周期归零。 4. 编码序列 编码方式:可选择连续序列或非连续序列,选择会影响后续包含哪些设置。 序列长度:序列包含多少位数字,可以设置1 – 18之间的整数。 序列起始值:数据编码序列的起始值,默认值为3。 当编码方式设置为非连续序列时,展示其余两个配置项。 步长类型:默认值为“自定义步长”,也可以设置成“1 – 10之间随机步长”。 步长:当选择“自定义步长”时,设置的步长即为真实步长。当选择“1 – 10之间随机步长”时,实际步长为1 – 设置值之间的随机整数。

    2024年6月20日
    2.8K00
  • 4.1.15 框架之网关协议

    一、多端协议 协议内容格式 请求头 头信息 headerMap "sec-fetch-mode" -> "cors" "content-length" -> "482" "sec-fetch-site" -> "none" "accept-language" -> "zh-CN,zh;q=0.9" "cookie" -> "pamirs_uc_session_id=241af6a1dbba41a4b35afc96ddf15915" "origin" -> "chrome-extension://flnheeellpciglgpaodhkhmapeljopja" "accept" -> "application/json" "host" -> "127.0.0.1:8090" "connection" -> "keep-alive" "content-type" -> "application/json" "accept-encoding" -> "gzip, deflate, br" "user-agent" -> "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36" "sec-fetch-dest" -> "empty" 图4-1-15-1 头信息 headerMap 请求地址 requestUrl 例如 http://127.0.0.1:8090/pamirs/DemoCore?scene=redirectListPage HTTP参数键值对 parameterMap url中queryString在服务端最终会转化为参数键值对。 请求体格式 请求体格式采用GraphQL协议。请求体格式分为API请求和上下文变量。以商品的test接口为例,请求格式如下。 API请求格式 query{ petShopProxyQuery { queryPage(page: {currentPage: 1, size: 1}, queryWrapper: {rsql: "(1==1)"}) { content { income id code creater { id nickname } relatedShopName shopName petTalents { id name } items { id itemName } } size totalPages totalElements } } } 图4-1-15-2 API请求格式 上下文变量 variables 请求策略requestStrategy 名称 类型 说明 checkStrategy CheckStrategyEnum 校验策略:RETURN_WHEN_COMPLETED -?全部校验完成再返回结果RETURN_WHEN_ERROR -?校验错误即返回结果 msgLevel InformationLevelEnum 消息级别:DEBUG("debug", "调试", "调试"),INFO("info", "信息", "信息"),WARN("warn", "警告", "警告"),SUCCESS("success", "成功", "成功"),ERROR("error", "错误", "错误")不设置,则只返回错误消息;上方消息级别清单,越往下级别越高。只有消息的级别高于或等于该设定级别才返回,否则会被过滤。 onlyValidate Boolean 只校验不提交数据 表4-1-15-1 请求策略requestStrategy 上下文变量式例如下。 { "requestStrategy": { "checkStrategy": "RETURN_WHEN_COMPLETED", "msgLevel":"INFO" } } 图4-1-15-3 上下文变量式例 响应体格式 协议响应内容包括data、extensions和errors三部分,extensions和errors是可缺省的。data部分为业务数据返回值。应用业务层可以在extensions中添加API返回值之外的扩展信息。extensions中包含success、messages和extra三部分,success标识请求是否成功。如果业务正确处理并返回,则errors部分为空;如果业务处理返回失败,则将错误信息添加到errors中。 正确响应格式示例如下。 { "data": { "petShopProxyQuery": { "queryPage": { "content": [ { "id": "246675081504233477", "creater": { "id": "10001" }, "relatedShopName": "oinone宠物店铺001", "shopName": "oinone宠物店铺001", "petTalents": […

    Oinone 7天入门到精通 2024年5月23日
    1.4K00
  • 3.5.6 DSL配置大全(略)

    因为默认视图很难满足客户的个性化需求,所以日常开发中view的配置是避免不了的。本系列篇是比较全面地介绍View配置的各个方面涉及:视图、字段、动作、布局等

    Oinone 7天入门到精通 2024年5月23日
    2.2K00
  • 5.1 CDM的背景介绍

    如果说低代码开发框架输出技术标准,CDM则是结合oinone技术特性和软件工程设计,让输出数据标准变成可能。 一、背景介绍 无法照搬的最佳实践 要了解引入CDM的初衷,得从互联网架构的演进开始,了解其过程,就知道为什么说Oinone的CDM是中台架构的最佳技术实践的核心!我们在2.2【互联架构做为最佳实践为何失效】一文中介绍过互联网技术发展的四个阶段,特别平台化到中台化的阶段,目的是在一套规范下让听的见炮火声音的团队自行决定业务系统发展,适用多业务线(或多场景应用)独立发展。 互联网架构在演进过程中碰到的问题跟企业数字化转型过程中碰到的问题是非常类似: 随着企业业务在线化后对系统性能、稳定都提出了更高的要求,而且大部分企业的内部很多系统相互割裂导致,导致很多重复建设,所以我们需要服务化、平台化。 同时没有一个供应商能解决企业所有商业场景问题,又需要多个供应商共同参与,所以把供应商类类比成各个业务线,在一套规范下让供应商自行决定业务系统发展 既然跟阿里当初在架构演进过程中碰到的问题非常类似,那么是不是照搬阿里中台架构方案到企业就好了?当然不是,因为历史原因阿里的中台架构是采用的平台共建模式:“让业务线研发以平台设计好的规范进来共同开发”,其本质还是平台主导模式,它是有非常大的历史包袱。我们想象各个供应商的共建一个交易平台或商品平台,那是多么荒唐的事情,平台化已经足够的复杂了,还让不同背景、不同企业的研发一起共建,最后往往导致企业架构负载过重,这时对企业来说便不再是赋能而是“内耗”。 那么如果没有历史包袱,我们重新设计,站在上帝视角去看有没有更好的方式呢?当然有 借鉴微软的CDM 这里我们借鉴微软的CDM理念,CDM这个概念最早是2016年微软宣布“以Dynamics 365的形式改造其CRM和ERP”战略时提出的。微软给它的定义是“用于存储和管理业务实体的业务数据库,而且是开箱即用的”。CDM不仅仅提供标准实体,它还允许用户建立个性化的实体,用户可以扩展标准实体也可以增加和标准实体相关的新实体。 CDM可能并不性感,但绝对是非常必要的。它成为了微软的很多产品的基础,是构建了无数业务领域的原型。同时微软也期望它能成为快速实现数据交换和迁移的标准,这个有点像菜鸟网络推出的奇门,让所有TMS、OMS、WMS都基于一套数据接口API进行互通,一套标准是为了解决一个行业问题,而不是具体某一个企业一个集团的问题。 我们发现CDM的理念跟我们想要的“企业级的数据标准”是非常吻合的。但是我们也不能照搬照抄,虽然微软的CDM很好的解决了数据割裂问题,但就模型来说就够大家喝一壶了,模型库非常庞大而且复杂,学习成本巨高。 数字化时代软件会产生新的技术流派 我们知道传统软件的设计理念:侧重在模型对业务支撑全面性上。优点体现为配置丰富,缺点模型设计过于复杂,刚开始有前瞻性,但在理解、维护都非常困难,随着业务发展系统原先的设计逐渐腐化,异常笨重。 而Oinone的CDM设计理念:侧重在简单、灵活、统一上,体现为在上层应用开发时,每一业务领域保持独立,模型简单易懂,并结合Oinone的低代码开发机制进行快速开发,灵活应对业务变化。 所以我更想说Oinone的CDM是微软CDM的在原有基础上,与互联网架构结合,利用Oinone低代码开发平台特性形成新的工程化建议。Oinone-CDM不以把模型抽象到极致,支撑“所有业务可能性”为目标,而是抽象80%通用的设计,保持模型简单可复用,来解决数据割裂问题,并保持业务线独立自主性,快速创新的能力。 图5-1-1 Oinone-CDM要解决的问题 二、Oinone的CDM本质是创新的工程化建议 引入CDM以后系统工程结构会有什么变化,跟大家认知的互联网架构有什么区别。 原本上层的业务线系统,需要调用各个业务平台提供的功能,增加CDM以后也就是我们右的图,每个业务线就像一个独立右边。看上去复杂了,其实对业务线来说更加简单了。 互联网整体平台化带来的问题: 业务线每次业务调整都需要给各个平台提需求 业务平台研发需要了解所有业务线的知识再做设计,对研发要求非常高 各个业务域的不同需求相互影响包括系统稳定性、研发对需求响应的及时性 结合oinone特性提出的新工程建议: 一些通用性模块继续以平台化的方式存在,能力完全复用。 业务线自建业务平台,保持业务线的独立性和敏捷性 业务线以CDM为原型,保证核心数据不割裂,形成一致的数据规范 图5-1-2 引入CDM概念后的工程结构对比 三、CDM思路示意图 该示例中OinoneCDM的商品域不仅仅提供标准实体,保证各个业务系统的对商品的通用需求、简单易懂,在我们星空系列业务产品中如全渠道运营、B2B交易等系统以此为基础建立属于自身个性化的实体,可以扩展标准实体也可以增加和标准实体相关的新实体。 带来的好处: 通过多种继承方式,继承后的模型可扩展模型本身、模型行为等,从而解决业务独立性问题。 通过CDM层统一数据模型,从而解决多应用数据割裂问题 图5-1-3 Oinone-CDM思路示意图

    2024年5月23日
    1.4K00

Leave a Reply

Please Login to Comment