泛型与多态瞎想

"抽象"即是一种"限定",将一类事物从万事万物剥离出来.比如人,是对我们自身的抽象,是对我们自身的定义与限定

1.泛型:
    先说说泛型,我认为无论类泛型还是方法泛型,都是对java类型及其行为的一种"抽象",或者说是"限定".具体的"限定"主要
    体现在泛型的类的定义中.比如在java中集合是比较典型的泛型代表,其中又以ArrayList为代表,那么在ArrayList
    中的泛型对哪种java类型与行为进行"抽象"与"限定"呢?直观的感觉是ArrayList中的泛型可以让程序员在使用集合时,其中的
    元素可以保证为同种类型,例如:List<String> list = new ArrayList<String>();保证集合中的元素都是String
    类型,这是集合泛型的主要特征.ArrayList中的泛型对集合中的元素的类型进行了"限定",如何限定的呢?泛型并不限定
    集合中元素的类型是什么,但是它限定了集合中的元素必须是同种类型的逻辑事实,这种事实的行为体现可以参看ArrayList
    类中定义的几个方法,或许可以体会集合泛型的"抽象"与"限定"是如何实现的.
    public E get(int index);
    public E set(int index, E element);
    public boolean add(E e);
    
    在比如下面的方法泛型定义:
    public <T> T[] toArray(T[] a)
    这同样是ArrayList中定义的一个方法,但它是一个方法泛型,方法泛型更多是用来"限定",参数与结果之间的契约关系
    上面的方法泛型限制了参数类型与返回类型之间必须是同种类型的数组.在比如:
    public <T> List<T> findList(T model); //参数为T,则参数必须是这种类型的列表
    public <T extends Number> T add(T one, T two); //约束加数与被加数以及返回类型必须要相同,且都必须是数字类型
    
    上面的几点分析我认为基本说明了java类泛型与方法泛型都是对java类型及其行为的"抽象"与"限定".java类泛型主要着眼于
    类成员变量之间,成员变量与方法之间,方法与方法之间,方法与参数返回结果之间的一些契约,这些契约集合在一起就成为类泛型
    的具体体现,而方法泛型则更简单,主要用于约束参数与返回结果之间的契约.
    
    泛型的本质其实是对:一组不同的对象,处于同一个"结构体"(一个类或方法)中表现出相同行为的一种抽象方式.
    具体说:List<String> list = new ArrayList<String>();与List<Integer> list = new ArrayList<Integer>();
    对于String与Integer(它们是不同的对象),当它们处于ArrayList集合(结构体)中时,它们表现出了相同的行为(add,get,set...).
    再比如:add(new Byte(1), new Byte(2));与add(new Integer(1), new Integer(2));
    对于Byte与Integer(它们是不同的对象),当它们处于方法add(结构体)中时,表现出了相同的行为.
    这里所说的相同的行为,可以理解为相同的"一组契约的集合",这里的契约不仅仅指方法,更广泛的契约是:
    [===类成员变量之间,成员变量与方法之间,方法与方法之间,方法与参数返回结果之间的这些组合在一起都可以称之为契约.===]
    
2.抽象与多态
    多态是伴随抽象而生的,如果没有抽象,我想也就没有多态概念.主要表现在重载,覆盖,多态参数等几种情况,
    是事物多样性的表现之一.前面已经说过:"抽象"即是一种"限定",将一类事物从万事万物剥离出来.抽象的目的
    我认为主要是为了减少代码的重复性,代码重用度高,使得系统具有可维护性,可扩展性,可重用性.但是并不是所有的
    抽象都是合理的,都是优秀的.如何判定抽象的合理性,没有一个具体的标准,如果非要给一个标准,通常可以认为:
    抽象的东西越具备可维护性,可扩展性,可重用性,则可以作为合理抽象的大致标准,但是大致来说我认为,
    对一个事物或是概念的认识越接近其本质,抽象通常会更合理,也更可用.对于多态的基本认知如下:
    A.多态概念
    多态:就是相同的行为,不同的实现。允许父类的引用变量指向一个子类的对象
    对同一个对象来说,做同一件事情,有不同的实现和结果。方法重写和重载。
    对同一件事情来说,不同的对象来做,也有不同的结果。动态参数和异构集合里面。
    B.基本多态
    同一个类中:表现为方法的重载;根据不同的条件,来做同一件事情。产生不同的结果。
    子类和父类:表现为方法的重写;根据每个子类不同的特征和行为,改变同一件事情做法(联系和差异的集中体现)。
    C.进阶多态
    多态参数(父类类型 || 接口类型);异构集合(为了统一管理有继承关系的不同类型的数据,存放为(父类的引用变量))。这2个是多态里面最常用的。
    一件大家都可以做的事情:(传递一个对象进来做)(父类/接口 形参)(子类对象||父类对象||实现接口类)
    父类可以做,子类可以做。但是又不想用重载或者重写来调用,而是只要会做这个事情,就随便你去做,不关心怎么做。
    
    "抽象"是要找到对象之间的共性,而"多态"是对象之间的个性体现,两者是对立统一的,是事物的两个方面.


3.多态与泛型的关系
    实际这两者之间没有什么联系,但是泛型往往与多态参数一起使用,再加上泛型有时会带有上下边界的概念,因此容易被
    两者弄糊涂.比如在三层架构中每个层次往往喜欢使用泛型类,这个地方有必要介绍一下超类中使用泛型的情况,三层架构
    超类多数情况喜欢使用实体类作为泛型抽象的对象,根据前面对泛型的分析进行对比当前具体的情况实体类作为泛型对象分析
    泛型的本质其实是对:一组不同的对象,处于同一个"结构体"(一个类或方法)中表现出相同行为的一种抽象方式.
    当前的情况:这里的一组对象即为实体类,这里的"结构体"即为各个层次的超类,那么在其中又有哪些共同行为呢?
    比如所有的实体都有保存,更新,删除等需求,这就是它们的共同行为.下面来比较一下泛型与多态参数之间的区别:
    public Integer save(T baseModel) //其中T是类泛型参数<T extends BaseModel>
    public Integer save(BaseModel baseModel)
    上面两个方法都是保存实体对象,但是区别还是很大的,从接受参数的角度,似乎都可以接受所有的实体参数,其实不然
    当泛型超类的泛型参数T没有被一个实际的类型参数化之前,它确实可以接受任意实体类型,但是程序通常不会直接使用
    没有参数化的泛型超类,而会在子类对泛型进行参数在直接使用子类,比如CoreAccount extends BaseModel
    上面的泛型方法实际变成了:public Integer save(CoreAccount baseModel) save方法只可以接受CoreAccount
    类型的参数.而多态参数类型的方法则不会存在这样的问题,总是可以接受所有的实体类型.从直观上可以感觉到多态参数
    的方式更一般化,这种超类实际跟工具类十分相似(HibernateTemplate),非常的通用,通常不会被由不同的实体继承实现,
    而通常由其他类来委托使用.而泛型超类则恰好相反,它们通常是由相应层的实体类继承来使用.
    
    这里有一个问题:既然多态参数的形式一个类就可以完成所有实体的保存,又何必使用泛型参数的超类形式呢?
    多态参数的方式通常代表着更高的内聚度,也代表这个类复用性也是相当高的,但是想通过一个类就完成所有的业务
    这是一种比较夸张的说法,以dao层的设计为例,HibernateTemplate可以认为是那个万能的类,但是要应对五花八门
    的业务需求时程序员可能要用到HibernateCallback,LockMode,hql语句等,不同的需求需要构建不同的hql,
    这会导致HibernateTemplate的抽象语义渗透到service层,因此我们通常需要创建一个dao层,然后由它们委托
    HibernateTemplate完成大部分业务,防止HibernateCallback,LockMode,hql语句等带有复杂语义的参数,
    向service渗透.那么dao层使用一个类行不行呢?这个通常是不行的,如果有10个实体类,需要保存业务,那么这个类
    就需要定义10save方法,这显然不好.是否需要每个实体都需要对应定义一个dao类呢?通常情况下可以这样处理,但也不是
    必须的,这需要程序员自己拿捏,但是无论怎样此时会出现一个问题.比如10个实体类都需要保存方法,更新方法等,你就会发现
    需要在10个接口中定义10个雷同的接口方法,这显然不好.此时就有了泛型超类的用武之地了,只需要在超类中定义一次,
    当泛型被具体的实体参数化之后,就相当于定义了10次一样.是否可以在超类定义多态参数的形式呢?当然也可以,但是这不太
    符合多态参数使用方式(作为工具方法单独使用,而不是继承).
    
    其实这种设计符合:功能内聚,接口多开;层层参数简单低耦合;层内参数复杂高内聚;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现这样的功能可以通过使用枚举、和多综合运用。具体实现步骤如下: 1. 定义一个枚举类,其中每个枚举值都对应一个接口类和实现类类。 ``` public enum RequestTypeEnum { TYPE_1(Request1.class, Service1.class), TYPE_2(Request2.class, Service2.class); private Class<? extends Request> requestClass; private Class<? extends Service> serviceClass; RequestTypeEnum(Class<? extends Request> requestClass, Class<? extends Service> serviceClass) { this.requestClass = requestClass; this.serviceClass = serviceClass; } public Class<? extends Request> getRequestClass() { return requestClass; } public Class<? extends Service> getServiceClass() { return serviceClass; } } ``` 2. 定义一个方法,根据入参获取对应的枚举值,并根据枚举值获取对应的接口类和实现类类。 ``` public <T extends Request, R extends Service> R getService(T request) { RequestTypeEnum requestTypeEnum = getRequestTypeEnum(request); Class<T> requestClass = (Class<T>) requestTypeEnum.getRequestClass(); Class<R> serviceClass = (Class<R>) requestTypeEnum.getServiceClass(); T typedRequest = objectMapper.convertValue(request, requestClass); return applicationContext.getBean(serviceClass).execute(typedRequest); } private <T extends Request> RequestTypeEnum getRequestTypeEnum(T request) { // 根据入参获取对应的枚举值 // ... return requestTypeEnum; } ``` 3. 定义一个统一的入口方法,根据不同入参用不同实体类接收,并调用方法获取对应的实现类并执行。 ``` @RequestMapping("/execute") public Object execute(@RequestParam("type") String type, @RequestBody Object request) { RequestTypeEnum requestTypeEnum = RequestTypeEnum.valueOf(type.toUpperCase()); Class<? extends Request> requestClass = requestTypeEnum.getRequestClass(); Request typedRequest = objectMapper.convertValue(request, requestClass); return getService(typedRequest); } ``` 通过以上步骤,我们就可以实现一个统一的请求入口,根据不同入参用不同实体类接收,根据不同的入参类获取对应的实现类并执行。同时,通过使用枚举、和多综合运用,我们可以让代码更加简洁、易读和易维护。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值