组合、继承、内部类什么时候用,该怎么设计?

组合、继承、内部类什么时候用,该怎么设计?

1、组合、继承、内部类什么时候用

(1)继承关系:

   ① 就是属于“同族”【类型相同】的类,从两个类的共同代码中抽取出来,作为父类;

   ② 当前类需要用到另外一个类中的所有方法【属于继承或实现了】

   ③ 当前类需要用到另外一个类中大量的属性、方法

(2)组合关系:

   ① 当前类【该类作为一个对象整体】的很多个方法是需要用到另外一个类中的部分或者全部属性、方法

   ② 当前类只是想对原类进行修饰【作为装饰器】

   ③ 静态代理

(3)内部类:

   ① 内部类跟本类关系密切,一般是只有本类才用得到)

一般定义成了private,当然也可以定义成public,当其他类也需要使用到它时,且其他类中需要对它进行一些扩展的话,可以通过继承关系实现

内部类作为一个对象整体, 代码量少、使用频率比较低[一两个地方需要用到]-----》内部类,而非组合关系

-----------------------------------------------------------------------------------------------------------------------------------------------------------

注意:其实内部类和组合关系差不多吧,要么一般使用频率低、且代码量不长,要么与本类系相关,只在本类中使用,就作为内部类啦

但是代码量比较多,就请抽取出去,封装成外部类,然后以组合的方式使用。

2、还有一些人性化设计,提醒程序员要进行些操作:

1、在继承关系中,为了提醒程序员不要忘记实现某个重要的方法,将该方法定义成抽象方法,相对应的该类就变成了抽象类啦;

2、在继承关系中,为了避免初始化方法中,程序员忘记传递参数给父类方法,在父类方法中,重载该方法的一个无参方法,然后有参方法中代码调用无参方法;

3、在继承关系中,子类通过调用父类的方法拿到某个值,但是方法的调用书写太长,需要重构一下父类,将原本在子类中调用的方法封装到父类,然后子类在调用父类的方法;

3、继承、组合、内部类分别举个栗子【该过程有人性化设计的点子】:

(1)继承关系[“同族”的类]:(这里就放Servlet2中的代码,Servlet1跟它相同)

■ 一开始Servlet1 和 Servlet2 中的代码:

package com.shan._extends;

import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class Servlet2 implements Servlet{
    private ServletConfig config;
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;    
    }
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println(config.equals("hello"));    
    }
    @Override
    public ServletConfig getServletConfig() {//返回ServletConfig,将ServletConfig对象暴露给子类访问,为啥?因为config是私有的哈哈
        return this.config;
    }
    @Override
    public String getServletInfo() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }
}

● 解决:将Servlet1 和 Servlet 中共同的所有方法抽取封装成一个类【然后因为是“同族”------类型相同,使用继承关系】

(这里就放Servlet1中的代码为例,Servlet1跟Servlet2 中抽取封装成一个叫 MyGernericServlet的父类[它的代码跟上面一开始的Servlet2代码一模一样])

package com.shan._extends;

public class Servlet1 extends MyGenericServlet{
    
}

☺ 人性化设计之提醒程序员不要忘记实现某个重要的方法,将该方法定义成抽象方法,相对应的该类就变成了抽象类

 * 每个Servlet最重要的便是处理请求service方法,所以父类中的service方法需要定义成抽象的
这里就放Servlet1中的代码为例,它的父类MyGernericServlet,仅仅是将service方法定义成抽象,然后它自身变成了抽象方法)
public class Servlet1 extends MyGenericServlet{

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("hello");
        String value = super.getServletConfig().getInitParameter("wang");
        System.out.println(value);
    }
}

☺ 人性化设计之子类通过调用父类的方法拿到某个值,但是方法的书写太长,需要重构一下父类,将原本在子类中调用的方法封装到父类,然后子类在调用父类的方法;

 * String value = super.getServletConfig().getInitParameter("wang"); 想获取参数[这样设计代码的书写太长,可读性差]
 ● 重构一下封装到父类,(前面的方法super.getServletConfig()想去掉,则应该封装到父类中的getInitParameter方法,原先父类中只有方法:getServletConfig(),还没有 getInitParameter 方法,
   看代码书写时就发现:super.getServletConfig().getInitParameter("wang"); 父类中已经有可以获取到该"servletConfig"

解决:只需要在父类中书写一个getInitParameter(Strig str)方法,其实方法里边就是 "servletConfig"对象.getInitParameter(str);
而 getInitParameter()等都是获取到ServletConfig 中的一些方法,①官方早就有写好了接口ServletConfig,②且后边我们还需要用到该接口的其他的方法,
所以这里选择:直接让父类实现官方定义的接口ServletCOnfig
● 最终在子类中效果:String value = super.getInitParameter("wang");
这里就放父类MyGernericServlet中的代码为例Servlet1中仅仅是将service方法 获取参数value的代码设计书写变短,
  变成 String value = super.getInitParameter("wang");)
abstract class MyGenericServlet implements Servlet, ServletConfig{
    private ServletConfig config;
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;    
    }

    
    @Override
    abstract public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException ;
    @Override
    public ServletConfig getServletConfig() {//返回ServletConfig
        return this.config;
    }
    

    @Override
    public String getServletInfo() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }
    
    /*******************  子类中少写的代码,就交给父类吧  ******************************/
    @Override
    public String getInitParameter(String name) {    //获取初始化参数的信息
        return config.getInitParameter(name);
    }
    
    @Override
    public String getServletName() {
        return config.getServletName();
    }
    
    @Override
    public ServletContext getServletContext() {
        return config.getServletContext();
    }

    
    @Override
    public Enumeration<String> getInitParameterNames() {
        return config.getInitParameterNames();
    }

}
 

☺ 人性化设计之初始化方法中,避免程序员忘记传递参数给父类方法,在父类方法中重载该方法的一个无参方法,然后有参方法中代码调用无参方法;

这里就放父类MyGernericServlet中的代码与初始化方法有关部分为例,和Servlet1中init方法--重写的是父类那个不带参数的方法)
//父类与初始化方法有关部分

abstract class MyGenericServlet implements  Servlet, ServletConfig{
    private ServletConfig config;
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;    
        this.init();
    }
    /**
     * 为了避免人们忘记传入参数【创建了一个无参init()给子类】【*人性化设计*】
     * @throws ServletException
     */
    public void init() throws ServletException{};
}
 
//Servlet1中init方法

public class Servlet1 extends MyGenericServlet{
    @Override
    public void init() throws ServletException {
        System.out.println("子类的初始化工作~");
    }
}

(2)组合关系 [部分或者全部属性、方法]: 举例---设计二叉树的结点类Entry。


(3)内部类(跟本类关系密切),代码量少时,就直接定义成内部类。
    举例1:当其他类也需要使用到它时,且其他类中需要对它进行一些扩展的话,可以通过继承关系实现,
         例如红黑树的结点就是在继承二叉树的Entry基础上加入颜色属性、其他方法的扩展的实现的。

        ■ 举例2:jdbcTempate 类中查询模板(原先代码如下):
        【这里既有内部类TeacherResultSetHandler、又有外部类IResultHandler的解释
//jdbcTempate 类中查询模板(原先代码如下):


public class JdbcTemplate {
    /**
     * DQL操作的模板    
     * @param sql    DQL操作的SQL模板(带有占位符?)
     * @param params SQL模板中?对应的参数值
     * @return        List结果集
     */
    public static List<Teacher> query(String sql, Object...params) {
        //贾琏欲执事
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<Teacher> teachers = new ArrayList<>();
        try {
            conn = DruidUtil.getConn();
            ps = conn.prepareStatement(sql);
            //设置参数占位符
            for(int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            rs = ps.executeQuery();
            //结果集处理
            while(rs.next()) {
                Teacher teacher = new Teacher();
                teacher.setId(rs.getLong("id"));
                teacher.setName(rs.getString("name"));
                teacher.setAge(rs.getInt("age"));
                teachers.add(teacher);
            }            
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        DruidUtil.close(conn, ps, null);
        return teachers;
    }
}
 

问题:结果集处理写死了,方式一:试图使用泛型(不可,因为后边例如 的rs.getLong("id");  确定下来,跟实体类中的属性有关)

解决:不要在此处理结果集,应该交给对应的DAO的具体实现类去处理,因为DAO具体实现类中有可以直接拿到实体类的各个属性;

 

☺代码重构

■ 代码1在外部封装一个接口IResultSetHandler

● IResultHandler定义成外部类的解释:因为咱的模板就工具模板,而假如:咱把List handle(ResultSet rs) 定义在了工具模板Template类里的话,

① 它不属于静态属性;(不该在Template类中)

② 其他类也需要实现它(公共属性) ---选择定义在外部。

/**
 * 结果处理器,规范处理结果集的方法名称
 * @author Huangyujun
 *
 */
public interface IResultHandler {
    //处理结果集[需要有返回值,即需要得到处理结果]
    List handle(ResultSet rs) throws Exception;
}

 ■ 代码2:Template类中查询方法:选择传入一个接口对象IResultSetHandler对象,然后在处理“结果集处理”位置的代码,调用IResultSetHandler对象.handle();

  ■ 代码3:DAO类的具体实现类TeacherDAOImpl中添加内部类TeacherResultSetHandler,然后调用模板工具类Template的查询方法时多加入一个TeacherResultSetHandler对象参数。

●TeacherResultSetHandler定义成内部类的解释:与本类TeacherDAOImpl息息相关,只在本类使用。

 

 

 
 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟庭小师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值