*下面的观点提供一下简单浏览,只因为下面的设计方式使用接口分离的原则便可以解决问题。
当然小型业务的话,很小很小的业务中,可以简单浏览下*
引言:数据管道流,“流”给我们的第一印象就是I/O流了吧,但是这个流是OOParser(面向对象解析器,和OOA没有关系)的,不是OOP的,
说到OO,就要进行抽象了,菜鸟要和大家分享下了:说的不对的地方,还望各路大神批评指正。
简介:DataPipeStream是根据自己编排的字母(OOParser)来定义的一种模式的体现,这个管道流(把管道从一端接通到另一端,进行目标的数据传输)的应用场景概要:对接口无法得知自己的子类拥有什么时,我们无法使用接口引用去访问子类的方法。我觉得传统的OO中,这种思想限制了我们说是:超类所拥有的方法只能小于等于子类,对于具体存在的现实世界的实物,这是一个拥有很高的正确性的定理(我的理解是这样), 但是对于抽象的小型业务模块的话,我认为(又一个我认为)这个定理使我们的编程变得更为复杂:
比如:在一个系统中的包含三个模块:
根据上述模块,拿第二个来说,宿舍管理模块又包含三个子模块:1、卫生管理,2、宿舍出入记录,3、宿舍信息管理;
假设用户的需求都有增删改查,那我们自然就会想到抽象出一个泛型接口出来;但是,为什么会有子模块,那是因为每个模块有的拥有除了公共方法之外的自己的方法,或者是为了后期的维护,那么问题来了:每个子模块(比如:卫生管理)拥有自己的方法的话,我们面向接口的话就访问不到子类的方法,怎么办呢?按照常理说,对于这种小业务级的,父模块知道自己的子模块可以做些什么事情,所以对于子类的业务,超类应该有必要得知自己的子类的所能做的事情,所以对于这种现状我们会遇到一些小问题,我使用方案来说明:
所有子类的独有的方法都在接口中声明,那么面向超类的话就可以访问所有的子类的方法了
宿舍管理模块:
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 宿舍管理模块
* Created by determination on 2017/5/28.
*/
public interface DormitoryManagementCommonService {
void save(T entity);
void delete(Serializable id);
void update(T entity);
T get(Serializable id);
/**
* DormitoryInfoService业务的方法:
* 根据学生姓名查询对应宿舍,可能会有名字一样的学生,所以返回的是一个列表
* @param sname 学生姓名
* @return 宿舍列表
*/
List queryBy(String sname);
/**
* DormitoryInOutService业务方法:
* 根据状态查询,宿舍进出记录是状态是出去还是进入,宿舍进出管理特有的方法
* @param state 进出的状态
* @return 根据状态查询出的所有的出入记录
*/
List queryByState(String state);
/**
* HygieneCheckService业务的方法:
* 根据宿舍卫生检查成绩进行查询
* @param score 卫生检查成绩
* @return 获得指定卫生成绩的卫生检查记录
*/
List queryByScore(double score);
}
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 宿舍出入管理子模块
* Created by determination on 2017/6/1.
*/
public class DormitoryInOutService implements DormitoryManagementCommonService {
@Override
public void save(DormitoryIO entity) { }
@Override
public void delete(Serializable id) { }
@Override
public void update(DormitoryIO entity) { }
@Override
public DormitoryIO get(Serializable id) {
return null;
}
// 不属于模块的方法
@Override
public List queryBy(String sname) {
return null;
}
@Override
public List queryByState(String state) {
return null;
}
// 不属于模块的方法
@Override
public List queryByScore(double score) {
return null;
}
}
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 宿舍信息管理子模块
* Created by determination on 2017/5/28.
*/
public class DormitoryInfoService implements DormitoryManagementCommonService {
@Override
public void save(Dormitory entity) { }
@Override
public void delete(Serializable id) { }
@Override
public void update(Dormitory entity) { }
@Override
public Dormitory get(Serializable id) {
return null;
}
@Override
public List queryBy(String sname) {
return null;
}
// 不属于模块的方法
@Override
public List queryByState(String state) {
return null;
}
// 不属于模块的方法
@Override
public List queryByScore(double score) {
return null;
}
}
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 卫生检查记录管理子模块
* Created by determination on 2017/5/28.
*/
public class HygieneCheckService implements DormitoryManagementCommonService {
@Override
public void save(HygieneCheckRecords entity) { }
@Override
public void delete(Serializable id) { }
@Override
public void update(HygieneCheckRecords entity) { }
@Override
public HygieneCheckRecords get(Serializable id) {
return null;
}
// 不属于模块的方法
@Override
public List queryBy(String sname) {
return null;
}
// 不属于模块的方法
@Override
public List queryByState(String state) {
return null;
}
@Override
public List queryByScore(double score) {
return null;
}
}
但是,所有的子类都要实现接口中所有的方法,这是违背了分模块开发的“初衷”,使我们的代码更难维护,所以方案一pass掉
jdk1.8有一个特性可以让我们给接口中的方法一个默认的实现,所以我们采取给所有的子类的特有的方法一个默认实现,然后所有子模块就可以根据自己的业务选择对接口中的某些方法进行实现:
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 宿舍管理模块
* Created by determination on 2017/5/28.
*/
public interface DormitoryManagementCommonService {
void save(T entity);
void delete(Serializable id);
void update(T entity);
T get(Serializable id);
/**
* DormitoryInfoService业务的方法:
* 根据学生姓名查询对应宿舍,可能会有名字一样的学生,所以返回的是一个列表
* @param sname 学生姓名
* @return 宿舍列表
*/
default List queryBy(String sname){
return null;
}
/**
* DormitoryInOutService业务方法:
* 根据状态查询,宿舍进出记录是状态是出去还是进入,宿舍进出管理特有的方法
* @param state 进出的状态
* @return 根据状态查询出的所有的出入记录
*/
default List queryByState(String state){
return null;
}
/**
* HygieneCheckService业务的方法:
* 根据宿舍卫生检查成绩进行查询
* @param score 卫生检查成绩
* @return 获得指定卫生成绩的卫生检查记录
*/
default List queryByScore(double score){
return null;
}
}
然后各个子模块就变成了下面的这个样子
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 宿舍出入管理子模块
* Created by determination on 2017/6/1.
*/
public class DormitoryInOutService implements DormitoryManagementCommonService {
@Override
public void save(DormitoryIO entity) {
}
@Override
public void delete(Serializable id) {
}
@Override
public void update(DormitoryIO entity) {
}
@Override
public DormitoryIO get(Serializable id) {
return null;
}
@Override
public List queryByState(String state) {
return null;
}
}
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 宿舍信息管理子模块
* Created by determination on 2017/5/28.
*/
public class DormitoryInfoService implements DormitoryManagementCommonService {
@Override
public void save(Dormitory entity) {
}
@Override
public void delete(Serializable id) {
}
@Override
public void update(Dormitory entity) {
}
@Override
public Dormitory get(Serializable id) {
return null;
}
@Override
public List queryBy(String sname) {
return null;
}
}
package cn.type.test;
import java.io.Serializable;
import java.util.List;
/**
* 卫生检查记录管理子模块
* Created by determination on 2017/5/28.
*/
public class HygieneCheckService implements DormitoryManagementCommonService {
@Override
public void save(HygieneCheckRecords entity) {
}
@Override
public void delete(Serializable id) {
}
@Override
public void update(HygieneCheckRecords entity) {
}
@Override
public HygieneCheckRecords get(Serializable id) {
return null;
}
@Override
public List queryByScore(double score) {
return null;
}
}
但是(又一个但是),这里面向超类的话,我们原来的意愿并不关心子类或者实现类是谁,我只关心超类,所以超类可以使用自己声明的方法,这也会违反我们分模块开发的“初衷”,所以方案二pass掉
依据上述方案二的弊端,我们需要在超类方法中声明的子类中的独有的方法时,加上一些限制:比如卫生管理,可以根据宿舍卫生分数来查询宿舍的卫生检查记录,根据分数查询,这是卫生管理模块所拥有的方法,只能卫生管理模块来调用,如果其他两个模块来调用这个方法时,就会抛出异常(将会表明,在这个方法对某个调用此方法的类是不可见的)
为每个子模块的特有的方法加上@PipeInterfaceAnnotation注解(表示将此方法加入到管道流中),并指定参数type(意思为此方法要在管道流中流向哪一个业务类),其他子模块的实现和方案二的一样,不用变
package cn.type.test;
import com.data.pipe.annotation.PipeInterfaceAnnotation;
import java.io.Serializable;
import java.util.List;
/**
* 宿舍管理模块
* Created by determination on 2017/5/28.
*/
public interface DormitoryManagementCommonService {
// 宿舍出入管理模块名称,为了向DataPipeStream中注入
String DORMITORYINOUT_SERVICE_NAME = "cn.type.test.DormitoryInOutService";
// 宿舍信息管理模块名称,为了向DataPipeStream中注入
String DORMITORYINFO_SERVICE_NAME = "cn.type.test.DormitoryInfoService";
// 卫生检查管理模块名称,为了向DataPipeStream中注入
String HYGIENECHECK_SERVICE_NAME = "cn.type.test.HygieneCheckService";
void save(T entity);
void delete(Serializable id);
void update(T entity);
T get(Serializable id);
/**
* DormitoryInfoService业务的方法:
* 根据学生姓名查询对应宿舍,可能会有名字一样的学生,所以返回的是一个列表
* @param sname 学生姓名
* @return 宿舍列表
*/
@PipeInterfaceAnnotation(type = DormitoryInfoService.class)
default List queryBy(String sname){
return null;
}
/**
* DormitoryInOutService业务方法:
* 根据状态查询,宿舍进出记录是状态是出去还是进入,宿舍进出管理特有的方法
* @param state 进出的状态
* @return 根据状态查询出的所有的出入记录
*/
@PipeInterfaceAnnotation(type = DormitoryInOutService.class)
default List queryByState(String state){
return null;
}
/**
* HygieneCheckService业务的方法:
* 根据宿舍卫生检查成绩进行查询
* @param score 卫生检查成绩
* @return 获得指定卫生成绩的卫生检查记录
*/
@PipeInterfaceAnnotation(type = HygieneCheckService.class)
default List queryByScore(double score){
return null;
}
}
测试一下:
package cn.type.test;
import com.data.pipe.stream.port.DataPipeStream;
import org.junit.Test;
/**
* 数据管道流测试类
* Created by determination on 2017/5/28.
*/
public class TestDataPipe {
@Test
public void test() {
DormitoryManagementCommonService commonService = (DormitoryManagementCommonService) DataPipeStream
.injectPipeStream(DormitoryManagementCommonService.DORMITORYINOUT_SERVICE_NAME);
commonService.queryByState("进入"); // 宿舍出入管理: 进入状态查询
/*
将会抛出异常:
java.lang.RuntimeException:
Pipe Method : queryByScore(...), It is invisible in cn.type.test.DormitoryInOutService.
*/
commonService.queryByScore(90.00);
}
}
所属:data-pipe-1.0.5.jar——百度云盘data-pipe-1.0.5jar及其依赖,提取码:iwij。
总结:数据管道流提供三种注入方法,通过类名注入、Class类型注入、对象注入,均可以使用,依赖jar:asm-5.1.jar、asm-commons-5.1.jar、asm-tree-5.1.jar、cglib-nodep-2.2.2.jar。
使用DataPipeStream.injectPipeStream()
进行注入,被注入的方法在这里称之为管道方法,核心思想,通过一个管道流对各个模块进行目标数据的关联,把模块之间的耦合(这里的耦合是必须的耦合,我们想要解除这种必须的耦合关系,重新思考,重新定义)使用管道流进行关联
初出茅庐,说的不正确之处还望各路大神批评指正