zoukankan      html  css  js  c++  java
  • java设计模式基础

    、单例模式(Singleton)

    1、单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处:

      1>某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销.

      2>省去了new操作符,降低了系统内存的使用频率,减轻GC压力.

      3>有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了.(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程.

    2、单例三步骤: 1.构造函数私有化2.类中创建一个本类对象3.提供一个方法可以获取该对象.

    3、对于该类的事物该怎么描述还是怎么描述,当需要内存中该类对象唯一时就加上面三步.

    4、懒汉式和饿汉式,延迟加载,实际中使用饿汉式,懒汉式有线程问题 (在判断是否为空时cpu切换,可以加sync..锁定,但是效率低).

    //饿汉式
    class Single{
        private static final Single s = new Single();
        private Single(){}
        public static Single getInstance(){
            return s;
        }
    }
    
    //懒汉式
    class Ehanshi(){
      private ehanshi(){} Ehanshi e = null;
      public static Ehanshi getInstance(){
        if(e==null){
          --》此处切换cpu,会有线程问题 
          e = new Ehanshi();
        }
      }
    }
    
    //解决方式一(效率低,每次需要判断是否锁定)
    class Ehanshi(){
      private ehanshi(){} Ehanshi e = null;
      public static Ehanshi synchronized getInstance(){
        if(e==null){ e = new Ehanshi();}
      }
    }
    //解决方式二 ,效率高 (但是还是建议使用饿汉式简单)
    class Ehanshi(){
      private ehanshi(){} Ehanshi e = null;
      public static Ehanshi getInstance(){
        if(e==null){
          synchronized(Ehanshi.class){
            if(e==null){
              e = new Ehanshi();
            }
          }
        }
      }
    }

    5、使用案例:

    例1:链接池可以使用单例模式,初始化的时候创建譬如100个connection对象,然后再需要的时候提供一个,用过之后返回到pool中,单例模式保证连接池有且只有一个.

    例2:Spring 的 IoC 容器在默认情况下对所有托管对象都是进行了单例化处理的,scope可以配置单例还是多例.

    例3:我们有时候项目简单的时候不想用spring,可以自己写工厂,工厂类做成单例.

    例4:web服务器中的token随机数生成器(给表单设置一个唯一 id)也是单例.

    ps:总之就是只需要用一个实例时,都可以使用单例.

    二、工厂模式

    建立一个工厂类,对实现了同一接口的一些类进行实例的创建,减少代码中大量的new,解耦合.spring的bean工厂,典型的大大的工厂模式.

    //单例,工厂
    public class ServiceFactory {
        
        private Properties serviceConfig = new Properties();
        //单例的构造函数也只执行一次
        private ServiceFactory(){
            InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("service.properties");
            try {
                serviceConfig.load(in);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        private static ServiceFactory instance = new ServiceFactory();
        public static ServiceFactory getInstance(){
            return instance;
        }
        public <T> T createService(Class<T> clazz){
            //clazz.getName()拿到的带包名
            String name = clazz.getSimpleName();
            String className = serviceConfig.getProperty(name);
            try {
                T service = (T) Class.forName(className).newInstance();
                return service;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    //service.properties
    BusinessService=cn.itcast.service.impl.BusinessServiceImpl
    BusinessService service = (BusinessService) ServiceFactory.getInstance().createService(BusinessService.class);

    三、适配器模式(Adapter)

    将一个类的接口转换成客户期望的另一个接口,让原本不兼容的接口可以合作无间.比如去德国手机充电问题.

    http://www.cnblogs.com/wangjq/archive/2012/07/09/2582485.html 这个讲的比较好.

    四、装饰模式(Decorator)

    1、装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例.

    2、装饰器模式的应用场景:

      1>需要扩展一个类的功能.

      2>动态的为一个对象增加功能,而且还能动态撤销.(继承不能做到这一点,继承的功能是静态的,不能动态增删.)

    public interface Sourceable {
        public void method();
    }
    
    public class Source implements Sourceable {
        public void method() {
            System.out.println("the original method!");
        }
    }
    
    public class Decorator implements Sourceable {
    
        private Sourceable source;
    
        public Decorator(Sourceable source) {
            this.source = source;
        }
    
        public void method() {
            System.out.println("before decorator!");
            source.method();
            System.out.println("after decorator!");
        }
    }
    
    public class DecoratorTest {
    
        public static void main(String[] args) {
            Sourceable source = new Source();
            Sourceable obj = new Decorator(source);
            obj.method();
        }
    }

    ps:参见javaEE(12)_数据库连接池的第一种实现,目标是拦截close方法.其实给用户的数据库连接是经过我包装后的连接对象,感觉装饰模式可以被动态代理取代.

    五、动态代理模式

    1、代理模式的应用场景:如果已有的方法在使用的时候需要对原有的方法进行改进,和装饰模式要实现的目的一样,但是更简便,不拦截的方法无需一一写出来.

    2、代理对象存在的价值:用于拦截对真实业务方法的访问,如在jdbc数据库连接池中使用动态代理拦截close方法,将连接放入连接池而不是关闭.

    3、原理就是:实际用户拿到的连接是代理对象而不是正在的Connection对象,代理类实现InvocationHandler类.

    http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

    动态代理应用:

    //1、jdbc数据库连接池中使用动态代理拦截close方法,将连接放入连接池而不是关闭:
    public synchronized Connection getConnection() throws SQLException {
        if(list.size()<=0){
            throw new RuntimeException("数据库忙,请稍会再来!!");
        }
        Connection conn = list.removeFirst();   //list.get()不行
        return new MyConnectionHandler(conn,this).getWarpConn();
    }
    
    class MyConnectionHandler implements InvocationHandler {
        private Connection realConnection;
        private Connection warpedConnection;
        private MyDataSource dataSource;
    
        private int maxUseCount = 5;
        private int currentUserCount = 0;
    
        MyConnectionHandler(Connection conn,MyDataSource dataSource) {
            this.realConnection=conn;
            this.dataSource = dataSource;
        }
    
        Connection getWarpConn() {
            warpedConnection = (Connection) Proxy.newProxyInstance(this
                    .getClass().getClassLoader(), new Class[] { Connection.class },this);
            return warpedConnection;
        }
       //proxy:把代理对象自身传递进来 method:代表当前调用的方法 args:调用方法的参数
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if ("close".equals(method.getName())) {
                currentUserCount++;
                if (currentUserCount < maxUseCount)
                    dataSource.connectionsPool.addLast(warpedConnection);
                else {
                    realConnection.close();
                    dataSource.currentCount--;
                }
            }
            return method.invoke(realConnection, args);
        }
    }
    
    //2、动态代理改写之前的解决全站乱码拦截器   *经典
    public class CharacterEncodingFilter implements Filter {
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
                throws IOException, ServletException {
    
            final HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
    
            request.setCharacterEncoding("UTF-8"); // 解决post乱码
    
            chain.doFilter((ServletRequest) Proxy.newProxyInstance(
                    CharacterEncodingFilter.class.getClassLoader(),
                    request.getClass().getInterfaces(), new InvocationHandler() {
    
                        public Object invoke(Object proxy, Method method, Object[] args) {
                            if (!method.getName().equals("getParameter")) {
                                return method.invoke(request, args);
                            }
                            if (!request.getMethod().equalsIgnoreCase("get")) {
                                return method.invoke(request, args);
                            }
    
                            String value = (String) method.invoke(request, args);
                            if (value == null) {
                                return null;
                            }
                            return new String(value.getBytes("iso8859-1"), "UTF-8");
                        }
    
                    }), response);
        }
    
        public void destroy() {
        }
    
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }
    
    //3、动态代理改写之前的压缩输出拦截器
    public class GzipFilter implements Filter {
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
                throws IOException, ServletException {
    
            final HttpServletRequest request = (HttpServletRequest) req;
            final HttpServletResponse response = (HttpServletResponse) resp;
    
            ResponseProxy proxy = new ResponseProxy(response);
            chain.doFilter(request, proxy.createProxy());
    
            byte[] out = proxy.getBuffer(); // 得到目标资源的输出
    
            System.out.println(new String(out, "UTF-8"));
    
        }
    
        class ResponseProxy {
            private ByteArrayOutputStream bout = new ByteArrayOutputStream();
            private PrintWriter pw = null;
    
            public byte[] getBuffer() {
                if (pw != null) {
                    pw.close();
                }
                return bout.toByteArray();
            }
    
            private HttpServletResponse response;
    
            public ResponseProxy(HttpServletResponse response) {
                this.response = response;
            }
    
            public HttpServletResponse createProxy() {
                return (HttpServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(),
                    response.getClass().getInterfaces(), new InvocationHandler() {
                        public Object invoke(Object proxy, Method method, Object[] args){
                            if (!method.getName().equals("getWriter")&&
                                    !method.getName().equals("getOutputStream")) {
                                method.invoke(response, args);
                            }
    
                            if (method.getName().equals("getWriter")) {//PrintWriter.write("中国");
                                pw = new PrintWriter(new OutputStreamWriter(bout, "UTF-8"));
                                return pw;
                            }
    
                            if (method.getName().equals("getOutputStream")) { 
                                return new ServletOutputStream() {
                                    @Override
                                    public void write(int b) throws IOException {
                                        bout.write(b);
                                    }
                                };
                            }
                            return null;
                        }
                    });
            }
        }
        public void destroy() {
        }
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }
    
    //4、动态代理+注解,实现权限管理
    //service方法中,权限可精确到具体的方法
    @Permission("添加分类")
    public void addCategory(Category c){
        cdao.add(c);
    }
    
    @Permission("查看分类")
    public Category findCategory(String id){
        return cdao.find(id);
    }
    
    public class ServiceFactory {
        
        private ServiceFactory(){}
        private static ServiceFactory instance = new ServiceFactory();
        public static ServiceFactory getInstance(){
            return instance;
        }
        
        public BusinessService createService(final User user){
            final BusinessService service = new BusinessServiceImpl();
            
            return (BusinessService) Proxy.newProxyInstance(ServiceFactory.class.getClassLoader(), 
                    service.getClass().getInterfaces(), new InvocationHandler(){
                
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                
                    //得到web层调用的方法
                    String methodName = method.getName();  //addCategory
                    
                    //反射出真实对象上相应的方法,检查真实对象方法上有没有权限注解
                    Method realMethod = service.getClass().getMethod(methodName, 
                            method.getParameterTypes());
                    Permission permission = realMethod.getAnnotation(Permission.class);
                    if(permission==null){
                        return method.invoke(service, args);
                    }
                    
                    //真实对象相应的方法上有权限注解,则得到访问该方法需要的权限
                    Privilege p = new Privilege(permission.value());//得到方法需要的权限
                    
                    //检查用户是否有权限  //AppContext ThreadLocal
                    //得到用户所有权限
                    if(user==null){
                        throw new SecurityException("您没有登陆");
                    }
                    
                    List<Privilege> list = service.getUserAllPrivilege(user);
                    if(list.contains(p)){
                        return method.invoke(service, args);
                    }
                    throw new SecurityException("你没有权限");
                }
            });
        }
    }
    
    public class CategoryServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            
            String method = request.getParameter("method");
            if("add".equals(method)){
                add(request,response);
            }
            if("getAll".equals(method)){
                getAll(request,response);
            }
        }
    
        private void getAll(HttpServletRequest request, HttpServletResponse response) 
                throws ServletException, IOException {
            BusinessService service = ServiceFactory.getInstance().
                    createService((User)request.getSession().getAttribute("user"));
            try{
                List list = service.getAllCategory(); 
                request.setAttribute("categories", list);
                request.getRequestDispatcher("/manager/listcategory.jsp").forward(request, response);
            }catch (Exception e) {
                if(e.getCause() instanceof SecurityException){
                    request.setAttribute("message",  e.getCause().getMessage());
                }
            }
        }
    
        private void add(HttpServletRequest request, HttpServletResponse response) 
                throws ServletException, IOException {
            BusinessService service = ServiceFactory.getInstance().
                    createService((User)request.getSession().getAttribute("user"));
            try {
                Category c = WebUtils.request2Bean(request, Category.class);
                c.setId(UUID.randomUUID().toString());
                service.addCategory(c);
                request.setAttribute("message", "添加成功");
            } catch (Exception e) {
                if(e.getCause() instanceof SecurityException){
                    request.setAttribute("message", e.getCause().getMessage());
                }else{
                    e.printStackTrace();
                    request.setAttribute("message", "添加失败");
                }
            }
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    
    }

    六、责任链模式

    参见:struts2基础中拦截器的实现原理.

    七、模板、策略模式

    模板方法:在定义功能时,功能的一部分是确定的,一部分是不确定的,那么就可以将不确定的部分暴露出去,让子类去完成.

    例:获取一段程序的执行时间
    abstract class GetRuntime{
      public final int getTime(){
        int start = System.currentTimeMillis();
        runCode();
        int end = System.currentTimeMillis();
        System.out.print(end - end)/1000;
      }
      abstract void runCode();
    }
    class Zi extends GetRuntime{
      void runCode(...)
      Zi z = new Zi();
      z.getTime();
    } 

    参见:javaEE(13)_jdbc框架

    八、享元模式

    java中常量池采用的就是享元设计模式,实际中做缓存时会采会用hashMap做一个享元,有的话直接拿,没有的话创建拿了再放进去.

    参见:javase(7)_Objcet类

    九、外观模式

    例如:service层的接口,封装所有的下层细节,对外暴漏简单的接口,这就是外观模式.

  • 相关阅读:
    小波变换的引入,通俗易懂
    Leetcode 437. Path Sum III
    Leetcode 113. Path Sum II
    Leetcode 112 Path Sum
    Leetcode 520 Detect Capital
    Leetcode 443 String Compression
    Leetcode 38 Count and Say
    python中的生成器(generator)总结
    python的random模块及加权随机算法的python实现
    leetcode 24. Swap Nodes in Pairs(链表)
  • 原文地址:https://www.cnblogs.com/wangweiNB/p/5218144.html
Copyright © 2011-2022 走看看