SpeedVan
2011-01-19 16:35
supernavy对持久层的观点方向和我基本相同。

持久化是一种纯技术,是一种Save&Load的手段,领域中并没有所谓的Save&Load,大家肯定玩过RPG游戏吧,当中的一个人,一个物体,一个怪物,自身是没有Save&Load功能的,是游戏提供的。这里我们可以看到领域是就是游戏内容本身,而架构就是游戏引擎本身,领域是现实的复写、镜像,所以Save&Load应该移到外面。很多人老是在对领域分析和设计时,老是会思考到持久化方式(不说数据库了,数据库只是一个例子而已),持久化的意义在于数据(对象、实体状态)放进去后,能持久保存,而且能还原出来。当中的持久方式,在此刻我们根本不用考虑,哪怕你序列化后用文本保存(supernavy提到)。只需要告诉框架,那些是需要持久的就可以了,其他不用再管了,否则持久化就侵入业务了。

过去我们把数据库操作放到领域中,就说侵入业务,不要认为封装了再放到领域中就不侵入了?披着羊皮的狼而已。

既然说到这些了,我就说说我最近的一些想法吧,我上面说到的,可能对于一些以信息管理的系统有些不合。的确,我一开始也怀疑自己的想法,但经过不断的反思后,我得到这样的一个观点:信息管理等这些不是单单持久化!信息管理尽管需要保存数据,但是一种带有组织,规范的信息(数据)。当然我们可以纳入数据库中,但这种做法,会让我们忽视他们的区别,这当中是两步过程:信息系统的信息收集,是以一种规范保存的(我们可以想成保存成excel),而持久化是把这样的一个excel持久起来(假设excel是易丢失的),而不是把信息持久化,信息的保存方式与持久方式是两回事

过去数据库思维,让我们把数据持久到数据库中,然后打开数据库看,对,就是这样的行为,让我们依赖了数据库,产生数据库思维,认为持久化后是可看的。现在的数据库,就是一个数据库和一个可以以某种方式来访问或者操作数据库的套件(现在所谓的数据库都是两件套)。试想,我们若果不关心持久方式,还会依赖数据库吗?——我们只会认为把东西放进,然后拿出来就好了。错的不是数据库,而是我们用错了数据库。扯远了~

[该贴被SpeedVan于2011-01-19 16:59修改过]

cuwkuhaihong
2011-01-19 17:53
这几天我要结婚,忙完了,再答复你们。先祝各位新年快乐!

cuwkuhaihong
2011-02-01 18:09
“如果现在能震撼过去,那么未来又能带给我们什么”,这句联通的广告说明了科技创新的力量与结果。在过去令人匪夷所思的东西现在都出现了。在第一次 工业革命(以蒸汽机的发明为标志)之前,人类很难想象将来会有不用任何动物拖动,就可以自由行走的车;第二次工业革命(以电的发现为标志)之前,人类同样很难想象将来会有这么多电器。这是人类美好的理想促使着社会的发展。同样现在没有东西不等于将来不会有。

再说对象设计,让程序准确描述对象,无人对此有异议,一旦描述出的对象,现实没有就可能因违背逻辑和常识而遭到耻笑。如一个酒吧的“吧台”,通常样子是,一张具备某种款式的桌子,里面可以摆放各式各样的酒。我开始违背常识,重新为该酒吧设计“吧台”,让它会推销酒水,当酒瓶放在“吧台”上的时候,吧台能显示这瓶就得相关信息,以及给出替代品,因为考虑到,它摆放在酒吧,是买酒的柜台,所以能增加一个推销功能。这与让狗能注册自己信息的例子是同样的,都是把常识中的一个事物变成为常识外一个例子。只不过前者可能比较容易实现,后者觉得不可能,所以从实现的可能性说:前者叫创新,后者叫幻想(其实实现也不难)。其中这样会推销的“吧台”已经问世一段时间。

这样的吧台会让酒吧运营更加轻松,至少站在吧台后面那个人会轻松,留出更多的精力关注业务,酒吧运营的业务逻辑丝毫未变。

酒吧的运营在现实环境是一套系统,酒吧老板,服务员,吧台,酒等对象,在酒吧的运营业务下把他们关联成一个系统;在软件系统也是多个不同对象+业务逻辑组成。在现实环境下使实体对象多功能,能让环境更加和谐;在虚拟的软件环境下,让对象多功能也能让软件环境更加和谐。二者系统性质相似,而有一个令人欣慰的不同是,在软件环境下,让对象多功能要比现实容易多了,所以我们可以让软件环境在和谐的路上大步前进,并让业务逻辑运营更加舒畅。

物极必反,让对象多功能也不能太离谱,要依附现实,但可超越现实。我们总不能给“吧台”增加喝酒的功能。

最初我提出的“智能对象”多有不妥,从此改名为“多功能对象”,这个名字比较合适。大家都认为原“智能对象”的remember()等方法名称有悖于逻辑。我把名称改一下:

// 在此输入java代码
public abstract class MObject extends Observable implements Serializable {
	/**
	 */
	private static final long serialVersionUID = 1L;

	public static final int REMEMBER = 1;
	public static final int FORGET = 2;
	public static final int UPDATE_MEMORY = 3;
	public static final int ASSOCIATE = 4;
	public static final int OBTAIN_ME = 5;
	public static final int FRESH_REMEMBER = 6;

	private boolean setupedObserver = false;

	/**
	 * 把对象自身持久。子类可以根据类的情况,重写该方法。 如该类是复合对象,想关联存储,则需要重写该方法
	 * 
	 */
	public abstract void saveSelf();

	
	/**
	 * 
	 * 匹配性删除对象对应的数据库记录,所谓“匹配性”就是根据参数删除该类对应的数据库中存储的实体
	 * 
	 * @param updateFields params
	 */
	public abstract void associateDelete(Object...params);
	
	
	/**
	 * 用于更新数据库记录,需要更新对象的某一个属性时,用到此方法。 
	 * 
	 * @param updateFields
	 *            属性的名称,如果你更改username的值,那么这个参数就应该是username, 注意不是username的值
	 */
	public abstract void updateSelfPropes(String... updateFields);

	/**
	 * 这是一个最自由的,最难以理解的,最惹争议的方法。所以在这里解释以下,该类方法名称可意为
	 * “联想”或者“匹配”,英语associate包含这两种解释,有一定哲学含义, 即:要素与一系列对象属性的匹配过程就叫联想。
	 * 默认实现是查询相关对象。意义是根据一个对象可以找到和它相关的对象。
	 * 
	 * 若该对象是一个事件,这是一个事件对象,那么你可以让他想到与这个事件相关的任何东西。 在子类中可以自己添加相关的‘associateXXX()’方法。
	 * 
	 * @param params
	 *            任何对象要素
	 * @return
	 */
	public abstract List<?> associate(Object... params);

	/**
	 * 根据主键数据库中获取自身全部信息
	 * 
	 * @param id
	 * @return
	 */
	public abstract void obtainMe();

	
	/**
	 * 
	 * @param obj
	 *            任何数据
	 */
	protected void notifyMyObservers(Object obj) {
		if (!isSetupedObserver()) {
			ThinObjectLoader.setupObservers(this);
		}

		this.setChanged();
		this.notifyObservers(obj);
	}

	public boolean isSetupedObserver() {
		return setupedObserver;
	}

	public void setSetupedObserver(boolean setupedObserver) {
		this.setupedObserver = setupedObserver;
	}

}
<p class="indent">


声明一下,这个类只不过是我的思想一个实现,不是标准,saveSelf(),你也可以写成saveXXX()。在使用时,根据具体环境实现该接口,比如saveSelf()方法你可以实现让它存储到数据库,文件等任何地方。我的一个实现就是:ThinObject持久方式采用的Thin。你可以使用hibernate/JPA。在实际开发中,让需要持久的对象继承ThinObject就可以了。

这里需要谈一个问题:“入侵”,首先说明一下什么叫“入侵”,入侵是指在某对象不需要某种事物的情况下,强行赋予了它该种事物。19世纪末八国联军进中国是“入侵”,但对外开放让外国人来中国做生意不算“入侵”;所以一个需要持久的对象继承了能够提供持久功能ThinObject也不算入侵。这恰是面向对象编程的优势。

没有必要太过于遵守条条框框,闭上眼睛想想,什么才是我们最想要的,才是发展起源。




[该贴被cuwkuhaihong于2011-02-01 18:10修改过]

SpeedVan
2011-02-03 14:01
我认为不想牵一发而动全身,高内聚低耦合,这才是我们想要的。在领域中,我们需要的是集中精力,攻克业务,纯技术层面的,应该是可装配,可替换的,甚至可以不要。带有数据库思维的话,新增一样东西,就会想到数据库增加一行。认为领域的增删改,就是数据库的增删改。其实不是,应该是(领域的)内存上,对象的增删改。软件里的数据交互是在(领域的)内存,不是硬盘。我们所说的XX业务,XX逻辑,全部都与持久化无关的。持久化是技术功能需要,但这并非领域业务需要。

我们所说的入侵,是指影响复用,影响替换,或者说让技术另领域模型不纯了。若果我用其他持久技术,却又不得不拖着这个ThinObject。除非,你把源代码的继承去掉,再编译一次

cuwkuhaihong
2011-02-06 16:15
2011年02月03日 14:01 "SpeedVan"的内容
顶一下我认为不想牵一发而动全身,高内聚低耦合,这才是我们想要的。在领域中,我们需要的是集中精力,攻克业务,纯技术层面的,应该是可装配,可替换的,甚至可以不要。带有数据库思维的话,新增一样东西,就会想到数据库增加一行。认为领域的增删改,就是数 ...


"不想牵一发而动全身,低耦合",我的设计也没有任何一点对此存有异议。何为“高内聚”还需要你解释一下。

我说过,任何一个对象参与业务逻辑的结果无非是对象属性和数量发生变化。

继承ThinObject是为了让对象具有变更属性和数量的能力,留出的精力投入的业务逻辑
上。ThinObject是这种想法一种实现,我是直接把对象持久到数据库中了,你可以写一个类似于ThinObject的东西,把它暂放的内存中,由其他机制负责数据库硬盘写入也是可以的,我对此没有异议。

这种顶级的抽象如何影响复用和替换了?这样的一个顶级继承如何让对象不纯了?

SpeedVan
2011-02-07 15:53
高内聚在我理解下,是划分边界后而进行内聚,领域中是领域模型内聚,而分层技术,则层内聚。所以不要把持久化搬到模型中。

不是对象不纯,而是领域模型,持久化技术是应该脱离模型的,也就是无论用户选什么持久化技术,最好都不影响领域模型。仓储方式Repository.setEntity(Entity entity)目的也是如此,把持久化技术放到Repository,甚至更远,而Entity则提供getter。这样,无论我改任何一种持久化技术,领域模型都不受影响。

你这个remeber是技术范畴,若果是领域中的模型remeber能力的,则在其内在应该存在一个记忆体(大脑,记事本),一个remeber则把引用set入这样的一个记忆体。领域实体是存在于内存,领域实体的交互都是在内存上。可见持久化技术是不存在领域中的。领域当中的所有增删改,都是(内存当中)对象的增删改(类似map,list的add、remove、update)。是框架得知实体产生,然后才产生持久事件(set入仓储时,或者set入cache时,框架得知)。

你这样的抽象,不是领域模型上的抽象,而是为了技术上支持而抽象,所以让技术入侵了领域。除非这个ThinObject存在jdk中,呵呵。仓储技术也是在这种追求而产生的另一种东西,你可以对比对比,感受感受。

cuwkuhaihong
2011-02-09 18:37
2011年02月07日 15:53 "SpeedVan"的内容
领域模型,持久化技术是应该脱离模型的,也就是无论用户选什么持久化技术,最好都不影响领域模型 ...


这句话说的没错,如果像我那样写ThinObject是把技术色彩带到领域对象中了,ThinObject只是一个例子,一个说明如果把对象变更自己属性的能力,甚至更多的能力,放入在自己身上是可行的,方便的。

当然,最好,最通用的做法是写一个DObject类,供领域对象继承,如此即避免了领域对象中染有持久技术的色彩,又满足了让对象变更自己属性的能力。

// 在此输入java代码
public abstract class DObject extends MObject{
	
	@Override
	public void saveSelf() {
		Repository.save(this);
	}

	@Override
	public void associateDelete(Object... params) {
		Repository.associateDelete(getClass(), params);
	}

	@Override
	public void updateSelfPropes(String... updateFields) {
		Repository.updatePropes(this, updateFields);
	}

	@Override
	public List<?> associate(Object... params) {
		return Repository.associate(getClass(), params);
	}

	@Override
	public void obtainMe() {
		Repository.load(this.getId());
	}

	abstract protected  Object getId() ;
}
<p class="indent">




[该贴被cuwkuhaihong于2011-02-09 18:39修改过]

猜你喜欢
2Go 上一页 1 2