我的BO
1-我的BO之强类型
2-我的BO之数据保护
数据保护指什么
软件的运行离不开数据,数据一般存在对象中。这种对象在 Java 统称为 POJO,在 C# 则为 POCO。若 POJO 的Property(属性)
都是可读写的(public
的 get
/set
),没有方法或只有少量的持久化方法,这种称为贫血模型。
贫血模型只存储数据而对数据没有控制,对象内部和外部都能修改。业务逻辑一般写在外部,就算写在内部也因为 Property 可由外界随意修改而控制不住数据。从而这个 POJO 只是存储数据,没有控制数据的能力,也就没有保护数据的能力。一个对象相关的逻辑不能被很好地集中管理,而是分散在各个外部方法中。从而产生了几个不良后果:
贫血模型缺点多
- 不同情况下对同份数据的处理有逻辑矛盾,且不易发现。如一处设属性值为
-1
,另一处却没有考虑值是-1
的情况。 - 相同的功能写多份,修改时容易改漏。经常复制粘贴的代码后果很可怕。
- 软件的质量很差,容易发生改了一个 Bug 产生两个 Bug。难以交付。
BO 如何保护数据
BO 中全部的 Property 对外都是只读的,外部无法直接修改 Property。只有 BO 自己内部才能修改属性,从而保护了数据。外部通过调用 BO 的业务方法修改一个或多个属性,业务方法可对参数和状态进行各种判断,满足条件才修改数据。从而保证任何时候 BO 的数据都是合法的。由于数据只能在内部修改,所以什么值代表什么意思是由 BO 自己决定的,统一决定,而不是由外部分散在各个地方的代码逻辑决定的,所以有效地保证了数据含义的统一性。
虽然关于这个 BO 自己的业务都写到 BO 这个类中了(这里暂无须考虑通过继承写到多个类的情况),起到了集中控制的效果。但内部不同的业务方法也可能有共用的逻辑,这些应该通过重构功能,以达到“一个功能只写一处”的状态。一个大功能会包含若干个小功能,这里的“功能”,是泛指大大小小的任何一个功能。无论是面向对象还是面向过程,都应该努力做到“一个功能只写一处”。这是解决软件灵活性与软件正确性的唯一比较可取的做法。除非把人当作机器,面对之前大量“复制粘贴再改改”的代码需要修改时也能毫不遗漏地全部修改。
BO 的实例化
BO 被定义为任何时刻都是有意义的,所以并不能new
一个空对象,然后再赋值,数据必须在new
时就送来,所以 BO 需要提供一个全部属性的构造方法。另外为了持久化方便的考虑,也可以接收一个 PO,从 PO 获取各个属性的值。
import com.abc.enumInfo.RepairStatus;
import com.abc.mybatis.model.Repair;
import com.abc.service.db.RepairDB;
import com.abc.util.BoTrackState;
public class RepairBo extends BoBase {
Repair repair;
@Autowired
RepairDB repairDB;
public RepairBo(Repair repair) { // 传入PO
if (repair == null)
throw ParameterException.missData("repair");
this.repair = repair;
}
public RepairBo(String code, Long depId, String reportUserName, String contactPhone, Date reportTime,
String address, Long createUserId, Date createTime, RepairStatus status) { // 传入每个属性
Repair entity = new Repair();
entity.setCode(code);
entity.setDepId(depId);
entity.setReportUserName(reportUserName);
entity.setContactPhone(contactPhone);
entity.setReportTime(reportTime);
entity.setAddress(address);
entity.setCreateUserId(createUserId);
entity.setCreateTime(createTime);
entity.setStatus(status.toString());
this.repair = entity;
this.trackState = BoTrackState.Added;
}
// region 属性
public Long getId() {
return repair.getId();
}
protected void setId(Long id) {
repair.setId(id);
setTrackUpdate();
}
public String getCode() {
return repair.getCode();
}
protected void setCode(String code) {
repair.setCode(code);
setTrackUpdate();
}
public Long getDepId() {
return repair.getDepId();
}
protected void setDepId(Long depId) {
repair.setDepId(depId);
setTrackUpdate();
}
public String getReportUserName() {
return repair.getReportUserName();
}
protected void setReportUserName(String reportUserName) {
repair.setReportUserName(reportUserName);
setTrackUpdate();
}
public String getContactPhone() {
return repair.getContactPhone();
}
protected void setContactPhone(String contactPhone) {
repair.setContactPhone(contactPhone);
setTrackUpdate();
}
public Date getReportTime() {
return repair.getReportTime();
}
protected void setReportTime(Date reportTime) {
repair.setReportTime(reportTime);
setTrackUpdate();
}
public String getAddress() {
return repair.getAddress();
}
protected void setAddress(String address) {
repair.setAddress(address);
setTrackUpdate();
}
public Long getCreateUserId() {
return repair.getCreateUserId();
}
protected void setCreateUserId(Long createUserId) {
repair.setCreateUserId(createUserId);
setTrackUpdate();
}
public Date getCreateTime() {
return repair.getCreateTime();
}
protected void setCreateTime(Date createTime) {
repair.setCreateTime(createTime);
setTrackUpdate();
}
public RepairStatus getStatus() {
String sStatus = repair.getStatus();
return RepairStatus.valueOf(sStatus);
}
protected void setStatus(RepairStatus status) {
String sStatus = status.toString();
repair.setStatus(sStatus);
setTrackUpdate();
}
// endregion 属性
// region 操作
public void delete() {
this.setTrackDeleted(); // 方法在base中
this.save(); // 方法在base中
}
// 业务方法: 派单
public void assignCheck() {
this.setStatus(RepairStatus.已派单);
this.save();
}
// 业务方法: 勘查
public void prospecting(String address) {
this.setAddress(address);
this.setStatus(RepairStatus.故障属实);
this.save();
}
// endregion 操作
不足之处
没有对构造时的数据进行合法性验证。解决办法可以在构造时检查,若非法则抛异常。也可以私有化构造方法,并提供public static
方法,若非法则返回null
。
感谢
感谢 Rayman(QQ:25625607) 在我为【BO 的属性该全只读,通过方法来修改】还是【可以部分属性可写(public set
),并在写时作业务逻辑】举棋不定时给我了肯定的回答。我认为这是整个 BO 的关键所在。