大家好,本文根据领域驱动设计的成果,实现了init API。

上一篇博文

从0开发3D引擎(十一):使用领域驱动设计,从最小3D程序中提炼引擎(第二部分)

下一篇博文

从0开发3D引擎(十三):使用领域驱动设计,从最小3D程序中提炼引擎(第四部分)

继续实现

实现“DirectorJsAPI.init”

实现“保存WebGL上下文”限界上下文

1、在src/api_layer/api/中加入DirectorJsAPI.re,实现API

DirectorJsAPI.re代码为:

  1. let init = DirectorApService.init;

2、在src/infrastructure_layer/external/external_object/中加入Error.re,负责处理“js异常”这个外部对象

Error.re代码为:

  1. //根据错误信息(string类型),创建并抛出“js异常”对象
  2. let error = msg => Js.Exn.raiseError(msg);
  3. //根据“js异常”对象,抛出它
  4. let throwError: Js.Exn.t => unit = [%raw err => {|
  5. throw err;
  6. |}];

3、在src/application_layer/service/中加入DirectorApService.re,实现应用服务

DirectorApService.re代码为:

  1. let init = contextConfigJsObj => {
  2. CanvasCanvasEntity.getCanvas()
  3. |> OptionContainerDoService.get
  4. //OptionContainerDoService.get函数返回的是Result容器的包装值,需要调用ResultContainerVO.bind函数来处理容器内部的值
  5. |> ResultContainerVO.bind(canvas => {
  6. SetWebGLContextSetWebGLContextDoService.setGl(
  7. contextConfigJsObj,
  8. canvas,
  9. )
  10. })
  11. //应用服务DirectorApService负责用抛出异常的方式处理Result错误
  12. |> ResultContainerVO.handleFail(Error.throwError);
  13. };

关于bind函数的使用,可以参考从0开发3D引擎(五):函数式编程及其在引擎中的应用->bind

4、修改CanvasCanvasEntity.re,实现getCanvas函数

CanvasCanvasEntity.re相关代码为:

  1. let getCanvas = () => {
  2. Repo.getCanvas();
  3. };

5、把最小3D程序的WebGL1.re放到src/infrastructure_layer/external/library/中,保留所有的代码

WebGL1.re代码为:

  1. open Js.Typed_array;
  2. type webgl1Context;
  3. type program;
  4. type shader;
  5. type buffer;
  6. type attributeLocation = int;
  7. type uniformLocation;
  8. type bufferTarget =
  9. | ArrayBuffer
  10. | ElementArrayBuffer;
  11. type usage =
  12. | Static;
  13. type contextConfigJsObj = {
  14. .
  15. "alpha": bool,
  16. "depth": bool,
  17. "stencil": bool,
  18. "antialias": bool,
  19. "premultipliedAlpha": bool,
  20. "preserveDrawingBuffer": bool,
  21. };
  22. [@bs.send]
  23. external getWebGL1Context:
  24. ('canvas, [@bs.as "webgl"] _, contextConfigJsObj) => webgl1Context =
  25. "getContext";
  26. [@bs.send.pipe: webgl1Context] external createProgram: program = "";
  27. [@bs.send.pipe: webgl1Context] external useProgram: program => unit = "";
  28. [@bs.send.pipe: webgl1Context] external linkProgram: program => unit = "";
  29. [@bs.send.pipe: webgl1Context]
  30. external shaderSource: (shader, string) => unit = "";
  31. [@bs.send.pipe: webgl1Context] external compileShader: shader => unit = "";
  32. [@bs.send.pipe: webgl1Context] external createShader: int => shader = "";
  33. [@bs.get] external getVertexShader: webgl1Context => int = "VERTEX_SHADER";
  34. [@bs.get] external getFragmentShader: webgl1Context => int = "FRAGMENT_SHADER";
  35. [@bs.get] external getHighFloat: webgl1Context => int = "HIGH_FLOAT";
  36. [@bs.get] external getMediumFloat: webgl1Context => int = "MEDIUM_FLOAT";
  37. [@bs.send.pipe: webgl1Context]
  38. external getShaderParameter: (shader, int) => bool = "";
  39. [@bs.get] external getCompileStatus: webgl1Context => int = "COMPILE_STATUS";
  40. [@bs.get] external getLinkStatus: webgl1Context => int = "LINK_STATUS";
  41. [@bs.send.pipe: webgl1Context]
  42. external getProgramParameter: (program, int) => bool = "";
  43. [@bs.send.pipe: webgl1Context]
  44. external getShaderInfoLog: shader => string = "";
  45. [@bs.send.pipe: webgl1Context]
  46. external getProgramInfoLog: program => string = "";
  47. [@bs.send.pipe: webgl1Context]
  48. external attachShader: (program, shader) => unit = "";
  49. [@bs.send.pipe: webgl1Context]
  50. external bindAttribLocation: (program, int, string) => unit = "";
  51. [@bs.send.pipe: webgl1Context] external deleteShader: shader => unit = "";
  52. [@bs.send.pipe: webgl1Context] external createBuffer: buffer = "";
  53. [@bs.get]
  54. external getArrayBuffer: webgl1Context => bufferTarget = "ARRAY_BUFFER";
  55. [@bs.get]
  56. external getElementArrayBuffer: webgl1Context => bufferTarget =
  57. "ELEMENT_ARRAY_BUFFER";
  58. [@bs.send.pipe: webgl1Context]
  59. external bindBuffer: (bufferTarget, buffer) => unit = "";
  60. [@bs.send.pipe: webgl1Context]
  61. external bufferFloat32Data: (bufferTarget, Float32Array.t, usage) => unit =
  62. "bufferData";
  63. [@bs.send.pipe: webgl1Context]
  64. external bufferUint16Data: (bufferTarget, Uint16Array.t, usage) => unit =
  65. "bufferData";
  66. [@bs.get] external getStaticDraw: webgl1Context => usage = "STATIC_DRAW";
  67. [@bs.send.pipe: webgl1Context]
  68. external getAttribLocation: (program, string) => attributeLocation = "";
  69. [@bs.send.pipe: webgl1Context]
  70. external getUniformLocation: (program, string) => Js.Null.t(uniformLocation) =
  71. "";
  72. [@bs.send.pipe: webgl1Context]
  73. external vertexAttribPointer:
  74. (attributeLocation, int, int, bool, int, int) => unit =
  75. "";
  76. [@bs.send.pipe: webgl1Context]
  77. external enableVertexAttribArray: attributeLocation => unit = "";
  78. "";
  79. [@bs.send.pipe: webgl1Context]
  80. external uniformMatrix4fv: (uniformLocation, bool, Float32Array.t) => unit =
  81. "";
  82. [@bs.send.pipe: webgl1Context]
  83. external uniform1i: (uniformLocation, int) => unit = "";
  84. [@bs.send.pipe: webgl1Context]
  85. external uniform3f: (uniformLocation, float, float, float) => unit = "";
  86. [@bs.send.pipe: webgl1Context]
  87. external drawElements: (int, int, int, int) => unit = "";
  88. [@bs.get] external getFloat: webgl1Context => int = "FLOAT";
  89. [@bs.send.pipe: webgl1Context]
  90. external clearColor: (float, float, float, float) => unit = "";
  91. [@bs.send.pipe: webgl1Context] external clear: int => unit = "";
  92. [@bs.get]
  93. external getColorBufferBit: webgl1Context => int = "COLOR_BUFFER_BIT";
  94. [@bs.get]
  95. external getDepthBufferBit: webgl1Context => int = "DEPTH_BUFFER_BIT";
  96. [@bs.get] external getDepthTest: webgl1Context => int = "DEPTH_TEST";
  97. [@bs.send.pipe: webgl1Context] external enable: int => unit = "";
  98. [@bs.get] external getTriangles: webgl1Context => int = "TRIANGLES";
  99. [@bs.get] external getUnsignedShort: webgl1Context => int = "UNSIGNED_SHORT";
  100. [@bs.get] external getCullFace: webgl1Context => int = "CULL_FACE";
  101. [@bs.send.pipe: webgl1Context] external cullFace: int => unit = "";
  102. [@bs.get] external getBack: webgl1Context => int = "BACK";

6、在src/domain_layer/domain/init/set_webgl_context/service/中加入SetWebGLContextSetWebGLContextDoService.re,创建领域服务SetWebGLContext

SetWebGLContextSetWebGLContextDoService.re代码为:

  1. let setGl = (contextConfigJsObj, canvas): ResultContainerVO.t(unit, Js.Exn.t) => {
  2. ContextContextEntity.setGl(contextConfigJsObj, canvas)
  3. |> ResultContainerVO.succeed;
  4. };

7、修改ContextContextEntity.re,实现setGl函数

ContextContextEntity.re相关代码为:

  1. let setGl = (contextConfigJsObj, canvas) => {
  2. ContextRepo.setGl(WebGL1.getWebGL1Context(canvas, contextConfigJsObj));
  3. };

8、修改ContextPOType.re,定义Context PO的gl字段的数据类型

ContextPOType.re相关代码为:

  1. type context = {
  2. gl: option(WebGL1.webgl1Context),
  3. ...
  4. };

9、修改ContextRepo.re,实现仓库对Context PO的gl字段的操作

ContextRepo.re代码为:

  1. let getGl = gl => {
  2. //将Option转换为Result
  3. Repo.getContext().gl |> OptionContainerDoService.get;
  4. };
  5. let setGl = gl => {
  6. Repo.setContext({...Repo.getContext(), gl: Some(gl)});
  7. };

10、修改CreateRepo.re,实现创建Context PO的gl字段

CreateRepo.re相关代码为:

  1. let create = () => {
  2. ...
  3. context: {
  4. gl: None,
  5. ...
  6. },
  7. };

实现“初始化所有Shader”限界上下文

1、重写DirectorApService.re

DirectorApService.re代码为:

  1. let init = contextConfigJsObj => {
  2. CanvasCanvasEntity.getCanvas()
  3. |> ResultContainerVO.bind(canvas => {
  4. SetWebGLContextSetWebGLContextDoService.setGl(
  5. contextConfigJsObj,
  6. canvas,
  7. )
  8. |> ResultContainerVO.bind(() => {InitShaderInitShaderDoService.init()})
  9. })
  10. |> ResultContainerVO.handleFail(Error.throwError);
  11. };

2、加入值对象InitShader

从0开发3D引擎(十):使用领域驱动设计,从最小3D程序中提炼引擎(第一部分)的“设计值对象InitShader”中,我们已经定义了值对象InitShader的类型,所以我们直接将设计转换为实现:

在src/domain_layer/domain/init/init_shader/value_object/中加入InitShaderInitShaderVO.re,创建值对象InitShader

InitShaderInitShaderVO.re代码为:

  1. type singleInitShader = {
  2. shaderId: string,
  3. vs: string,
  4. fs: string,
  5. };
  6. type t = list(singleInitShader);

3、在src/domain_layer/domain/shader/shader/value_object/中加入ProgramShaderVO.re,创建值对象Program,它的DO对应一个WebGL的program对象

ProgramShaderVO.re代码为:

  1. type t =
  2. | Program(WebGL1.program);
  3. let create = program => Program(program);
  4. let value = program =>
  5. switch (program) {
  6. | Program(value) => value
  7. };

4、修改聚合根ShaderManager的DO

根据识别的引擎逻辑:

  • 在初始化所有Shader时,创建每个Program
  • 在渲染每个三角形时,根据Shader名称获得关联的Program

我们需要根据Shader id获得关联的Program,所以在ShaderManager DO中应该加入一个immutable hash map,它的key为Shader id,value为值对象Program的DO。

应该在领域视图的“容器”限界上下文中,加入值对象ImmutableHashMap、值对象MutableHashMap,其中ImmutableHashMap用于实现不可变的hash map,MutableHashMap用于实现可变的hash map。

现在来具体实现它们:

1)在src/domain_layer/domain/structure/container/value_object/中创建文件夹hash_map/

2)在hash_map/文件夹中加入ImmutableHashMapContainerVO.re、MutableHashMapContainerVO.re、HashMapContainer.re、HashMapContainerType.re

ImmutableHashMapContainerVO.re负责实现Immutable Hash Map;

MutableHashMapContainerVO.re负责实现Mutable Hash Map;

HashMapContainer.re从两者中提出的公共代码;

HashMapContainerType.re定义HashMap的类型。

因为HashMapContainer需要使用reduce来遍历数组,这个操作属于通用操作,应该作为领域服务,所以在领域视图的“容器”限界上下文中,加入领域服务Array。在src/domain_layer/domain/structure/container/service/中加入ArrayContainerDoService.re,创建领域服务Array。

相关代码如下:

ArrayContainterDoService.re

  1. let reduceOneParam = (func, param, arr) => {
  2. //此处为了优化,使用for循环和mutable变量来代替Array.reduce
  3. let mutableParam = ref(param);
  4. for (i in 0 to Js.Array.length(arr) - 1) {
  5. mutableParam := func(. mutableParam^, Array.unsafe_get(arr, i));
  6. };
  7. mutableParam^;
  8. };

HashMapContainerType.re

  1. type t('key, 'value) = Js.Dict.t('value);
  2. type t2('value) = t(string, 'value);

HashMapContainer.re

  1. let createEmpty = (): HashMapContainerType.t2('a) => Js.Dict.empty();
  2. let get = (key: string, map: HashMapContainerType.t2('a)) =>
  3. Js.Dict.get(map, key);
  4. let entries = (map: HashMapContainerType.t2('a)): array((Js.Dict.key, 'a)) =>
  5. map |> Js.Dict.entries;
  6. let _mutableSet = (key: string, value, map) => {
  7. Js.Dict.set(map, key, value);
  8. map;
  9. };
  10. let _createEmpty = (): Js.Dict.t('a) => Js.Dict.empty();
  11. let copy = (map: HashMapContainerType.t2('a)): HashMapContainerType.t2('a) =>
  12. map
  13. |> entries
  14. |> ArrayContainerDoService.reduceOneParam(
  15. (. newMap, (key, value)) => newMap |> _mutableSet(key, value),
  16. _createEmpty(),
  17. );

ImmutableHashMapContainerVO.re

  1. type t('key, 'value) = HashMapContainerType.t('key, 'value);
  2. let createEmpty = HashMapContainer.createEmpty;
  3. let set =
  4. (key: string, value: 'a, map: HashMapContainerType.t2('a))
  5. : HashMapContainerType.t2('a) => {
  6. let newMap = map |> HashMapContainer.copy;
  7. Js.Dict.set(newMap, key, value);
  8. newMap;
  9. };
  10. let get = HashMapContainer.get;

MutableHashMap.re

  1. type t('key, 'value) = HashMapContainerType.t('key, 'value);
  2. let createEmpty = HashMapContainer.createEmpty;
  3. let set = (key: string, value: 'a, map: HashMapContainerType.t2('a)) => {
  4. Js.Dict.set(map, key, value);
  5. map;
  6. };
  7. let get = HashMapContainer.get;

现在我们可以通过修改ShaderManagerShaderEntity.re来修改ShaderManager的DO,加入programMap字段

ShaderManagerShaderEntity.re相关代码为:

  1. type t = {
  2. ...
  3. programMap:
  4. ImmutableHashMapContainerVO.t2(ShaderShaderEntity.t, ProgramShaderVO.t),
  5. };

5、创建领域服务BuildInitShaderData,实现构造值对象InitShader

1)在src/domain_layer/domain/init/init_shader/service/中加入BuildInitShaderDataInitShaderDoService.re,创建领域服务BuildInitShaderData

BuildInitShaderDataInitShaderDoService.re代码为:

  1. let build = () => {
  2. ShaderManagerShaderEntity.getAllGLSL()
  3. |> List.map(((shaderName, glsl)) => {
  4. (
  5. {
  6. shaderId: ShaderShaderEntity.getId(shaderName),
  7. vs: GLSLShaderVO.getVS(glsl),
  8. fs: GLSLShaderVO.getFS(glsl),
  9. }: InitShaderInitShaderVO.singleInitShader
  10. )
  11. });
  12. };

2)修改GLSLShaderVO.re,实现getVS、getFS函数

GLSLShaderVO.re相关代码为:

  1. let getVS = glsl =>
  2. switch (glsl) {
  3. | GLSL(vs, fs) => vs
  4. };
  5. let getFS = glsl =>
  6. switch (glsl) {
  7. | GLSL(vs, fs) => fs
  8. };

3)修改ShaderManagerShaderEntity.re,加入getAllGLSL函数

ShaderManagerShaderEntity.re相关代码为:

  1. let getAllGLSL = () => {
  2. ShaderManagerRepo.getAllGLSL();
  3. };

4)修改ShaderManagerRepo.re,加入getAllGLSL函数

ShaderManagerShaderEntity.re相关代码为:

  1. let getAllGLSL = () => {
  2. Repo.getShaderManager().glsls
  3. |> List.map(((shaderId, (vs, fs))) => {
  4. (ShaderShaderEntity.create(shaderId), GLSLShaderVO.create((vs, fs)))
  5. });
  6. };

6、在src/domain_layer/domain/init/init_shader/service/中加入InitShaderInitShaderDoService.re,创建领域服务InitShader

InitShaderInitShaderDoService.re代码为:

  1. let init = (): ResultContainerVO.t(unit, Js.Exn.t) => {
  2. ContextContextEntity.getGl()
  3. |> ResultContainerVO.bind(gl => {
  4. //从着色器DO数据中构建值对象InitShader
  5. BuildInitShaderDataInitShaderDoService.build()
  6. |> ResultContainerVO.tryCatch(initShaderData => {
  7. initShaderData
  8. |> List.iter(
  9. (
  10. {shaderId, vs, fs}: InitShaderInitShaderVO.singleInitShader,
  11. ) => {
  12. let program = ContextContextEntity.createProgram(gl);
  13. /* 注意:领域服务不应该直接依赖Repo
  14. 应该通过实体ContextContextEntity而不是ShaderManagerRepo来将program设置到ShaderManager PO的programMap中!
  15. */
  16. ContextContextEntity.setProgram(shaderId, program);
  17. ContextContextEntity.initShader(vs, fs, program, gl)
  18. |> ignore;
  19. //用于运行测试
  20. Js.log((shaderId, vs, fs));
  21. })
  22. })
  23. });
  24. };

7、修改ContextContextEntity.re,实现相关函数

ContextContextEntity.re相关代码为:

  1. let getGl = () => {
  2. ContextRepo.getGl();
  3. };
  4. ...
  5. let createProgram = gl => gl |> WebGL1.createProgram;
  6. let setProgram = (shaderId, program) => {
  7. ShaderManagerRepo.setProgram(shaderId, program);
  8. };
  9. let _compileShader = (gl, glslSource, shader) => {
  10. WebGL1.shaderSource(shader, glslSource, gl);
  11. WebGL1.compileShader(shader, gl);
  12. WebGL1.getShaderParameter(shader, WebGL1.getCompileStatus(gl), gl)
  13. === false
  14. ? {
  15. let message = WebGL1.getShaderInfoLog(shader, gl);
  16. //这里为了实现“从0开发3D引擎(十):使用领域驱动设计,从最小3D程序中提炼引擎(第一部分)”提出的“处理错误优化”,用“抛出异常”而不是Result来处理错误
  17. Error.error(
  18. {j|shader info log: $message
  19. glsl source: $glslSource
  20. |j},
  21. );
  22. }
  23. : shader;
  24. };
  25. let _linkProgram = (program, gl) => {
  26. WebGL1.linkProgram(program, gl);
  27. WebGL1.getProgramParameter(program, WebGL1.getLinkStatus(gl), gl) === false
  28. ? {
  29. let message = WebGL1.getProgramInfoLog(program, gl);
  30. //这里为了实现“从0开发3D引擎(十):使用领域驱动设计,从最小3D程序中提炼引擎(第一部分)”提出的“处理错误优化”,用“抛出异常”而不是Result来处理错误
  31. Error.error({j|link program error: $message|j});
  32. }
  33. : program;
  34. };
  35. let initShader = (vsSource: string, fsSource: string, program, gl) => {
  36. let vs =
  37. _compileShader(
  38. gl,
  39. vsSource,
  40. WebGL1.createShader(WebGL1.getVertexShader(gl), gl),
  41. );
  42. let fs =
  43. _compileShader(
  44. gl,
  45. fsSource,
  46. WebGL1.createShader(WebGL1.getFragmentShader(gl), gl),
  47. );
  48. WebGL1.attachShader(program, vs, gl);
  49. WebGL1.attachShader(program, fs, gl);
  50. WebGL1.bindAttribLocation(program, 0, "a_position", gl);
  51. _linkProgram(program, gl);
  52. WebGL1.deleteShader(vs, gl);
  53. WebGL1.deleteShader(fs, gl);
  54. program;
  55. };

8、修改ShaderManagerPOType.re,ShaderManager PO加入programMap字段

虽然programMap也是hash map,但不能直接使用领域层的值对象ImmutableHashMapContainerVO来定义它的类型!因为PO属于基础设施层,它不能依赖领域层!

因此,我们应该在基础设施层的“数据”中创建一个ImmutableHashMap.re模块,尽管它的类型和函数都与ImmutableHashMapContainerVO一样。

在src/infrastructure_layer/data/中创建文件夹structure/,在该文件夹中加入ImmutableHashMap.re。

为了方便,目前暂时直接用ImmutableHashMapContainerVO来实现ImmutableHashMap。

ImmutableHashMap.re代码为:

  1. type t2('key, 'a) = ImmutableHashMapContainerVO.t2('key, 'a);
  2. let createEmpty = ImmutableHashMapContainerVO.createEmpty;
  3. let set = ImmutableHashMapContainerVO.set;

修改ShaderManagerPOType.re,ShaderManager PO加入programMap字段:

  1. type shaderManager = {
  2. ...
  3. programMap: ImmutableHashMap.t2(shaderId, WebGL1.program),
  4. };

9、修改ShaderManagerRepo.re,实现setProgram函数

ShaderManagerRepo.re相关代码为:

  1. let _getProgramMap = ({programMap}) => programMap;
  2. let setProgram = (shaderId, program) => {
  3. Repo.setShaderManager({
  4. ...Repo.getShaderManager(),
  5. programMap:
  6. _getProgramMap(Repo.getShaderManager())
  7. //这里也使用基础设施层的“数据”的ImmutableHashMap,因为操作的是ShaderManager PO的programMap
  8. |> ImmutableHashMap.set(shaderId, program),
  9. });
  10. };

10、修改CreateRepo.re,实现创建ShaderManager PO的programMap字段

CreateRepo.re相关代码为:

  1. let create = () => {
  2. ...
  3. shaderManager: {
  4. ...
  5. programMap: ImmutableHashMap.createEmpty(),
  6. },
  7. };

实现用户代码并运行测试

1、在项目根目录上执行webpack命令,更新wd.js文件

  1. yarn webpack

2、实现index.html相关代码

index.html代码为:

  1. <script>
  2. ...
  3. //准备webgl上下文的配置项
  4. var contextConfig = {
  5. "alpha": true,
  6. "depth": true,
  7. "stencil": false,
  8. "antialias": true,
  9. "premultipliedAlpha": true,
  10. "preserveDrawingBuffer": false,
  11. };
  12. wd.Director.init(contextConfig);
  13. </script>

3、运行测试

运行index.html页面

打开控制台,可以看到打印了两次数组,每次数组内容为[Shader名称, vs, fs],其中第一次的Shader名称为“shader2”,第二次为“shader1”

从0开发3D引擎(十二):使用领域驱动设计,从最小3D程序中提炼引擎(第三部分)的更多相关文章

  1. 从0开发3D引擎(十):使用领域驱动设计,从最小3D程序中提炼引擎(上)

    目录 上一篇博文 下一篇博文 前置知识 回顾上文 最小3D程序完整代码地址 通用语言 将会在本文解决的不足之处 本文流程 解释本文使用的领域驱动设计的一些概念 本文的领域驱动设计选型 设计 引擎名 识 ...

  2. 从0开发3D引擎(十一):使用领域驱动设计,从最小3D程序中提炼引擎(第二部分)

    目录 上一篇博文 本文流程 回顾上文 解释基本的操作 开始实现 准备 建立代码的文件夹结构,约定模块文件的命名规则 模块文件的命名原则 一级和二级文件夹 api_layer的文件夹 applicati ...

  3. iOS 11开发教程(十二)iOS11应用视图始祖——UIView

    iOS 11开发教程(十二)iOS11应用视图始祖——UIView 在Swift中,NSObject是所有类的根类.同样在UIKit框架(UIKit框架为iOS应用程序提供界面对象和控制器)中,也存在 ...

  4. Senparc.Weixin.MP SDK 微信公众平台开发教程(十二):OAuth2.0说明

    紧接上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明>,这里专讲OAuth2.0. 理解OAuth2.0 首先我们通过一张图片来了解一下OAu ...

  5. 从0开发3D引擎(补充):介绍领域驱动设计

    我们使用领域驱动设计(英文缩写为DDD)的方法来设计引擎,在引擎开发的过程中,领域模型会不断地演化. 本文介绍本系列使用的领域驱动设计思想的相关概念和知识点,给出了相关的资料. 上一篇博文 从0开发3 ...

  6. Python开发【第二十二篇】:Web框架之Django【进阶】

    Python开发[第二十二篇]:Web框架之Django[进阶]   猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...

  7. 《C++游戏开发》笔记十二 战争迷雾:初步实现

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9475979 作者:七十一雾央 新浪微博:http:/ ...

  8. 网站开发进阶(四十二)巧用clear:both

    网站开发进阶(四十二)巧用clear:both 前言 我们在制作网页中用div+css或者称xhtml+css都会遇到一些很诡异的情况,明明布局正确,但是整个画面却混乱起来了,有时候在IE6下看的很正 ...

  9. 【小梅哥FPGA进阶教程】第十二章 数字密码锁设计

    十二.数字密码锁设计 本文由山东大学研友袁卓贡献,特此感谢 实验目的 实现数字密码锁设计,要求矩阵按键输出且数码管显示输入密码,密码输入正确与否均会有相应标志信号产生. 实验平台 芯航线FPGA核心板 ...

随机推荐

  1. Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplicated"}的解决方法

    左侧菜单栏时,发现点击路由跳转相同地址 会有这个报错 Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplic ...

  2. idea 为模块添加Tomcat依赖 解决: Intelij IDEA 创建WEB项目时没有Servlet的jar包

    解决: Intelij IDEA 创建WEB项目时没有Servlet的jar包 今天创建SpringMVC项目时 用到HttpServletRequest时, 发现项目中根本没有Servlet这个包, ...

  3. php利用curl发送 post get del put patch 请求

    因为需要在php开发中对接其它接口需要用php  curl去对接其它接口  我把他们封装成函数 希望能对大家有所帮助 这里面是封装好的  会自动把data进行转成json格式   同时解码成php数组 ...

  4. java静态方法和静态字段

    public class Dog{ public static void main(String[]args){ A a= new A(); a.add(); //java实例对象可以访问类的静态方法 ...

  5. VS编译release版本的出现的LNK1104 无法打开文件“libboost_filesystem-vc140-mt-1_58.lib

    最近在用restbed和vs2015做一个项目,debug编译的没问题,但是编译release就有问题,困扰了一天,说下我的出坑过程. 1.我用到了外部的库 restbed ,首先要想正确编译过,你的 ...

  6. 微信小程序的标签和html标签比较

    html 小程序 <div></div> <view></view> <h1><h2>....<h6> <p& ...

  7. 59)PHP,管理员表中所存在的项

    用户ID 用户名 用户密码 用户权限(就是他的角色等级,比如是1级  2级,  三级等等) 上次登录的IP 上次登录的时间

  8. @EnableWebMvc WebMvcConfigurer CorsConfig

    package me.zhengjie.core.config; import org.springframework.context.annotation.Configuration; import ...

  9. asp.net 获取日期

    //获取日期+时间 DateTime.Now.ToString(); // 2008-9-4 20:02:10 DateTime.Now.ToLocalTime().ToString(); // 20 ...

  10. 二、RabbitMQ简介及AMQP协议

    RabbitMQ简介 RabbitMQ是开源的消息代理和队列服务器,是由Erlang语言开发的,基于AMQP协议(Advanced Message Queuing Protocol高级消息队列协议)的 ...