案例分析:设计模式与代码的结构特性

  • 1、什么是设计模式(Design Patterns):

         设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

  • 2、最近用到以及上课涉及到的设计模式有工厂模式、抽象工厂模式、代理模式、建造者模式

    拿最近学习的mybatis框架中的应用举例

import com.itheima.dao.UserDao;
import com.itheima.domain.User; 
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class MybatisTest {
    private UserDao userDao;
    private SqlSession sqlSession;
    private InputStream in;
    @Before
    public void before() throws Exception{
        // 获取字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 根据字节输入流建立SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//建造者模式
        // 使用SqlSessionFactory生产SqlSession
        sqlSession = factory.openSession();// 工厂模式
        // 使用SqlSession获取Dao的代理对象
        userDao = sqlSession.getMapper(UserDao.class);// 代理模式

    }
@After
public void after () throws Exception{ // 释放资源 sqlSession.commit(); sqlSession.close(); in.close(); }
@Test
public void testFindAll() { List<User> users = userDao.findAll(); for (User user : users) { System.out.println(user); } } @Test public void testSaveUser(){ User user = new User(); user.setSex("女"); user.setBirthday(new Date()); user.setAddress("山东青岛"); user.setUsername("小明"); userDao.saveUser(user); List<User> all = userDao.findAll(); for (User user1 : all) { System.out.println(user1); } } }

上面有用到建造者模式,工厂模式以及代理模式,下面以个人浅显的=见解进行说一下简单的理解:

  • 2.1 建造者模式
     SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//建造者模式
在这里用到的建造者模式中 in(字节输入输入流)相当于构建工厂的图纸,你要建一个工厂,构建者模式相当于一个包工队,收到你给的图纸,按照图纸的要求来构建一个工厂。
进入SqlSessionFactoryBulider类中发现里面有好多种重载的bulid()方法.通过阅读发现bulid()方法中通过调用
XMLConfigBuilder()方法来解析xml文件(也就是我说的图纸)来解析图纸按照图纸的要求构建。
public class SqlSessionFactoryBuilder {

  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }

  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }

  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }

  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment) {
    return build(inputStream, environment, null);
  }

  public SqlSessionFactory build(InputStream inputStream, Properties properties) {
    return build(inputStream, null, properties);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
    
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

}

 使用建造者模式有什么好处呢?

     可以将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

  • 2.2 工厂模式
    sqlSession = factory.openSession();// 工厂模式
同样的我们看一下factory里有什么东东,发现里面好多种重载的openSession方法,所以说调用工厂模式时可以方便的用工厂模式进行生产我想要的类型的类。换而言之使用者只需要提出不同的需求,具体的产生细节可以忽略掉提高开发效率。
public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

  

  •      2.3  代理模式
     userDao = sqlSession.getMapper(UserDao.class);// 代理模式
首先将UserDao接口的代码拿过来
public interface UserDao {
    /**
     *  查询所有用户
     * @return
     */
    @Select("select * from user")
    List<User> findAll();

    /**
     *  保存用户信息
     * @param user
     */
    @Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
    void saveUser(User user);
}

  通过这种方式我可以不用去写UserDao接口的实现类而是直接利用代理模式进行加强。可以理解为代理商,代理商从总公司提货,对货物进行自己想要的包装(比如加价格,送附赠品),而代理商本身没有生产货物,只是代理、进货、卖货。

        为什么要用代理模式?

        中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

         开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

 

  以上为个人结合最近学习用到的代理模式的简单初步的见解,如有错误,谢谢指正。




posted @ 2019-12-08 21:33  Sunmengjie  阅读(108)  评论(0编辑  收藏  举报