大道至简,一点拙见!

12-11-25 abbasky
1、如果我有一个魔法袋子,它能装下世界。袋子装的不是单一品种,要装什么东西还临时起意,想到啥装啥。我们的程序要怎样来表达呢?
2、实体又是什么,看的见摸得着的就是实体吗?你能完整描述一个实体吗?如果不能,那么有什么机制可以轻易改动你的实体模型,而不改变原有的实体呢?
3、世界是错综复杂的关联着的,要怎样去描述这些关联呢?世界是变化的,关联也同样在变化的,怎样应变这种变化呢?
4、实体和实体之间经常存在关系,例如所有者的关系、对等的如朋友、兄弟的关系等等。有时候两者的关系还存在共同拥有的东西,比如结婚的双方持有的婚姻。

***************************************************************************

1、先说说实体:我认为实体只是表示一个独一无二的存在,他长什么样都不要紧,就算两个实体长的一模一样没有任何差别,它们也是独立存在的。所以我认为给它一个ID就可以了吧。

// 实体类
public class Entity{
       public final String id;
}
<p class="indent">

2、再说说我的魔法袋子,是实体持有的袋子,自然是有持有者的,能真正表达持有者的也只有实体的ID而已。那袋子到底是什么呢?用程序的说法,它是对象的属性,袋子是可以用破的,可以丢失的,就算是人的手都有可能失去。如果用属性,程序将没有弹性可言。所以我认为魔法袋子只是一个域Field。代码如下所示:

// 实体域类
public class Field{
       public final String id;
       public String name;
       public String type;
       public String ownerId; // 实体的id
       public String contactId
}
<p class="indent">

代码中contactId表达的是实体间的关联关系。


3、而问题3和4,直接上代码,实体可以通过域持有数据,数据可以是任何类型,任何数量级的,到此魔法袋终于诞生了。

// 在此输入java代码
public class Data{
       public final String contactId;
       public Object value;
}
<p class="indent">


不善表达,简单的拙见,欢迎讨论。

















3
banq
2012-11-25 15:05
问答形式写得不错,角度独特,魔法袋概念很萌。希望你能再多谈些,可能有助于别人能从你的角度来看这个问题。

[该贴被banq于2012-11-25 18:05修改过]

abbasky
2012-11-25 20:09
我的困惑:
1、一个项目随着功能不断增加,实体类变得越来越臃肿,很多时候实体类中的属性是为了方便而设置的,但利用率却很低,最后看这个实体,已经没有特征可言,从而引起的问题是对象限制越多,就越僵硬,没有弹性可言。
2、实体间的关联如何能够非常松耦合,比如我说的魔法袋装豆子,一般思维是以魔法袋持有豆子的集合的方式来表达,袋子不是专门用来装豆子的,我们如何能够让袋子独立于豆子呢?
3、在DDD开发中,我们通过根实体取出一长串的对象,所以我们要发明一种懒加载技术。我希望能非常自然地看到10个魔法袋,然后如果想看看里面装着什么,再去把袋子打开,看看里面装着什么货。

我曾用过数据库DB4O,数据可对象的引用层次过多会是一个恶梦,因此,我在想能够找到一个豆子是豆子,装在哪都是豆子自己,袋子是袋子,装什么都是袋子自己这样一种非常松散的对象管理模式。我想这种模式对于并发将是非常有利的,一种不需要锁的非常自然地并发方式也许就可以实现了。

banq
2012-11-27 09:28
2012-11-25 20:09 "@abbasky"的内容
数据可对象的引用层次过多会是一个恶梦,因此,我在想能够找到一个豆子是豆子,装在哪都是豆子自己,袋子是袋子,装什么都是袋子自己这样一种非常松散的对象管理模式 ...


你这个想法应该是一个正确的方向,我结合这篇帖子总结了一下,可能还是我们的思维角度不够立体,只从一个方面考虑问题,有些片面导致的。

这个片面的角度应该是只从需求分析解剖这个角度考虑,这个角度目标主要是想把需求中的领域模型表达出来,表达得越细腻越好,就像拆开一个复杂的机械,我们只考虑拆开,研究里面的结构,但这些都只是静态,至于这些结构如何协调实现机械运行的,使用这种方式是无法得知。

有点类似西医解剖,把尸体解剖开,知道脏器组成结构,但是中医强调的经络却无法观察到,因为经络运行必须在活动运行的人体上才有。

我们需要另外一个角度加进来,也就是在设计阶段,还要考虑领域模型的运行状态,你的问题可能就变成:我们魔术师已经知道魔法袋里装的什么,但是也必须等待进入现场表演需要时,才把魔法袋打开。也就是说:领域模型不必一开始加载其所有的属性或子对象,而是等待程序运行时,当用户发出命令,激活了事件,事件带着用户的指令与能量点燃魔法袋子,启动魔法袋的打开,也就是所谓的懒加载。

这种方式我已经在Jdonframework中用Java探索成功:解道为什么这么快,当然,直接使用FP语言本身就具备懒加载也不错,不过,它们是否支持我们这种基于数据库的懒加载还是一个问题。当然Hibernate那种懒加载周期太短,它是基于用户一个请求,一个请求实际是一个事件,而我们需要的是跨事件,但不是跨用户Session,而是应用级别的。




lovemelovemycode
2012-11-28 09:09
hibernate 不是已经实现懒加载了吗?

banq
2012-11-28 09:20
2012-11-28 09:09 "@lovemelovemycode"的内容
hibernate 不是已经实现懒加载了吗? ...


这种即用即加载和Hibernate的延迟加载或AJAX的异步加载是有区别的,AJAX的异步加载会发出很多Http请求;而Hibernate等延迟加载是无法跨请求的,只能在一个请求响应发往客户端结束前全部完成(Open Session in View)。

而基于Jdonframework+disruptor的即用即加载是跨请求的,也就是说,只有当第一次输出JSP页面时,需要访问模型对象的getXXX方法时,才会从数据库中加载。

SpeedVan
2012-11-29 12:07
实体无疑就是一种定义而已,定死了当然难以变化,当对待一个比较稳定的领域的时候,写死了会获取效率,对于“稳定”的理解在于,人类对该领域探索程度,这只有深入的领域人员才能作出“比较”合情的判断。

对于一些不是具体某种日常的领域(比较常见,而稳定的一般是研究方面),通过定义关系主体,来获取更松耦合。

但其实又是一样的,若果关系发生变化,我们改变的又是关系而已,其实也就是说变化什么改变什么。其实就是抽取不变的部分进行定义,变化部分通过关系描述,若果关系变化再变化就通过关系的关系描述,纵观所有语言中,比较有逻辑关系处理的非函数式莫属(逻辑式的话太偏了),而无法定义关系的语言,处理起来就相当辛苦(不是不行,而是这些语言的初衷不是这些,如JAVA这些,产生一堆冗杂的文件不说,引起效率问题更严重)。

siberian
2012-11-29 16:47
建议你看看网游的服务器中地设计。你的想法已经被实现。

abbasky
2012-12-08 09:28
经过多日的思考,终于把这个命题想清楚了,并进行了实施,效果不错。现在跟大家分享下:
1、在我看来世界任何事物存在都是独一无二的,必定存在这样一个接口。

public interface IReference
    {
        String id { get; }
    }
<p class="indent">


2、任何实体都是有类型的,万物以类分,以群分。

public class Entity : IReference
  {

      public Entity(String id, String type)
        {
            _id = id;
            _type = type;
	    }

        private String _id;

        public String id
        {
            get
            {
                return _id;
            }
        }

        private String _type;

        public String type
        {
            get
            {
                return _type;
            }
        }
}
<p class="indent">


3、世界任何事物,包括世界本身都是有更小的东西构成,这些东西小到如细胞、原子,大到如人的手臂,一个国家,甚至银河系。一样事物在成为另一事物一部分的时候,总是会有个名字(或隐含的名字)。比如一只手安在人身上叫手,安在野兽身上叫爪子。如此,成为部分的事物就成了data。

    public class Field : IReference
    {
       
        public Field(String fieldId)
        {
            _id = fieldId;
        }

        public Field(String fieldId,  String ownerId)
        {
            _ownerId = ownerId;
            _id = fieldId;
        }

        public Field(String fieldId, String ownerId, String name)
        {
            _ownerId = ownerId;
            _id = fieldId;
            _name = name;
        }
       
	    //所有者;
	 protected String _ownerId;

        public String ownerId
        {
            get
            {
                return _ownerId;
            }

            set
            {
                _ownerId = value;
            }

        }

        //自身的身份标识
        private String _id;

        public String id
        {
            get
            {
                return _id;
            }
        }

        //域的名称;
        protected String _name;

        public String name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
     
        protected Object _data;

        public Object data
        {
            get
            {
                return _data;
            }

            set
            {
                _data = value;              
            }
            
        }

    }
<p class="indent">


有了这几个元素,怎么来构成世界呢?现以一个有名字域的实体为例子,上代码:

public class EntityExam
    {
        
        public EntityExam()
        {           
            //创建实体,可以在创建时直接写入缓存或数据库
             
             _entity = new Entity(id, "有名实体");
        }

        private Entity _entity;
        public Entity entity
        {
            get
            {
                //if (_entity == null) return null;
                return _entity;
            }

        }
        protected Field _name;
        public String name
        {
            get
            {
                     if (_name == null)
                      {
                           List<Field> fields = DBService.GetField(new Field(null,  _entity.id, "名称"));
                            if (fields == null || fields.Count == 0) return "";
                             _name = fields[0];
                       }
                       return _name.data as String;
            }
            set
            {
                if (_name == null)
                {
                    List<Field> fields = DBService.GetField(new Field(null,  _entity.id, "名称"));
                    if (fields == null || fields.Count == 0)
                    {
                        _name = new Field(DBService.GetNextId(), _entity.id, "名称");
                    }
                    else
                    {
                        _name = fields[0];
                    }
                }
                _name.data = value;
                DBService.SetField(_name);
            }

        }
}
<p class="indent">


这样做的好处是,你在不同的应用中可以共用数据,但在不同应用中同一个事物有不同侧面的表达,互不影响,因为我们从任何一个角度看到的世界都是不完整的,呈现的是一个个“相”而已。同时这样做可以实现属性级别的懒加载,而不像DDD中通过根实体来加载所有数据。
欢迎大家一同讨论》

[该贴被abbasky于2012-12-08 09:31修改过]

猜你喜欢