zoukankan      html  css  js  c++  java
  • Java Design Patterr

    Factory:

    ●简介:

    工厂模式同单例模式一样,也是Java中最常用的设计模式之一,属于创建型模式,它提供了一种创建对象的最佳方式。能够根据要求调用者提供的信息为接口指定不同的实现类,降低耦合。

    ●接口及其实现类

    package factory;
    
    public interface Sender {
        public void send();
    }
    复制代码
    package factory;
    
    public class SmsSender implements Sender{
    
        @Override
        public void send() {
            System.out.println("用短信发送...");
        }
    }
    复制代码
    复制代码
    package factory;
    
    public class EmailSender implements Sender{
    
        @Override
        public void send() {
            System.out.println("用电子邮箱发送...");
        }
    }
    复制代码

    ●简单工厂

    复制代码
    package factory;
    /**
     * 普通工厂模式,可以需求生产对象
     * 缺点:面对复杂的初始化,会使代码变得巨大
     *      每添加一个实现类都要修改代码,违反了里氏替换原则
     *      可能会产生null对象,引发 空指针异常
     * @author wqj24
     *
     */
    public class GeneraSenderFactory {
        
        public Sender produceSender(String msg) {
            
            // 根据消息,指定具体实现类
            if ("email".equals(msg)) {
                return new EmailSender();
            }
            
            if ("sms".equals(msg)) {
                return new SmsSender();
            } 
            
            // 没有符合要求的产品
            return null;
        }
    }
    复制代码

    上面的缺点就是,每写添加一个实现类就要改工厂类的代码,我们可以通过反射解决这一痛点。

    ●简单工厂(反射)

    复制代码
    package factory;
    /**
     * 简单工厂的优化
     * 优点:使用反射,避免了添加子类就要修改工厂对象
     */
    public class GeneraSenderFactory01 {
        
        public Sender produceSender(Class<? extends Sender> clazz) {
            
            Sender sender = null;
            
            try {
                sender = (Sender) clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            
            return sender;
        }
    }
    复制代码

    如果面对初始化复杂的对象,上面那的代码会变得很长,结构性差,可以为每个子类都写一个工厂方法。

    ●多个工厂方法

    复制代码
    package factory;
    
    /**
     * 多工厂,每个方法负责生产各自的实例 优点可以应对复杂的初始化
     * 优点:不会产生 null 对象
     *      每个方法负责自己对象的初始化工作,结构清晰。
     */
    public class ManySenderFactory {
        
        public Sender produceEmail() {
    
            return new EmailSender();
        }
    
        public Sender produceSms() {
    
            return new SmsSender();
        }
    }
    复制代码

    也可以将上面的方法改写成静态的,这样就可以不用new对象,直接通过类名调用工厂方法了。

    Singleton:

    • 单例模式,确保某个类只能生成一个实例
    • 单例模式的构造方法必须定义为私有(private)的
    • 必须要定义一个静态(static)的方法,作为生成这个对象实例的入口
    复制代码
    package com.singleton;  
    //静态代码块不一定在最开始执行,比如说 静态代码块 放在 单例模式中,  
    //但一般情况下 静态代码块是第一执行的 也就是在类加载时执行, 只执行一次  
    class SingletonTest  
    {  
        private static SingletonTest singletonTest = new SingletonTest();  
        static  
        {  
            System.out.println("======java 静态代码块========");  
        }  
      
      
        private SingletonTest()  
        {  
            System.out.println("java实现单例模式");  
        }  
          
        public static SingletonTest getInstance()  
        {  
      
            return singletonTest;  
        }  
      
    }  
      
    public class Singleton  
    {  
        public static void main(String[] args)  
        {  
            SingletonTest st = SingletonTest.getInstance();  
            SingletonTest st2 = SingletonTest.getInstance();  
    
                      //返回true,这两个实例是一样的  
        System.out.println(st == st2);  
    }  
    复制代码

    prototype:

      原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。本小结会通过对象的复制,进行讲解。在Java中,复制对象是通过clone()实现的,先创建一个原型类:

    复制代码
    public class Prototype implements Cloneable {  
      
        public Object clone() throws CloneNotSupportedException {  
            Prototype proto = (Prototype) super.clone();  
            return proto;  
        }  
    }
    复制代码

      很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,我会在另一篇文章中,关于解读Java中本地方法的调用,此处不再深究。在这儿,我将结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念:

      浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

      深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

    proxy:

    动态代理(运行期行为)主要有一个 Proxy类 和一个 InvocationHandler接口

    动态代理角色:

    1. 抽象主题角色

    2. 真实主题角色(实现了抽象主题接口)

    3. 动态代理主题角色(实现了 InvocationHandler接口,并实现了 invoke()方法)

    Proxy 要调用 newProxyInstance方法

    代码演示:

    1.抽象主题角色 SubjectDemo.java

    复制代码
    package com.dynamicproxy ;  
      
    public interface SubjectDemo  
    {  
        public void request() ;  
    }
    复制代码

    2. 真实主题角色 RealSubjectDemo.java

    复制代码
    package com.dynamicproxy ;  
      
      
    public class RealSubjectDemo implements SubjectDemo  
    {  
        public void request()  
        {  
            System.out.println("实现了某请求") ;  
        }  
    }  
    复制代码
     

    3. 动态代理主题角色 DynamicProxySubjectDemo.java

    复制代码
    package com.dynamicproxy ;  
      
    import java.lang.reflect.InvocationHandler ;  
    import java.lang.reflect.Method ;  
      
      
    public class DynamicProxySubjectDemo implements InvocationHandler  
    {  
        private Object sub ;  
      
        public DynamicProxySubjectDemo(Object obj)  
        {  
            this.sub = obj ;  
        }  
      
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
        {  
            System.out.println("before"+method) ;  
      
            method.invoke(sub, args) ;//真实的调用方法操作  
      
            System.out.println("after"+method) ;  
      
            return null ;  
      
        }  
      
      
    }  
    复制代码
     

    4.客户端 Client.java

    复制代码
    package com.dynamicproxy ;  
      
    import java.lang.reflect.InvocationHandler ;  
    import java.lang.reflect.Proxy ;  
      
    public class Client  
    {  
        public static void main(String[] args)  
        {  
            RealSubjectDemo rsd = new RealSubjectDemo() ;  
      
            InvocationHandler handler = new DynamicProxySubjectDemo(rsd) ;  
             
            Class<?> classType = handler.getClass() ;  
              
            // classType.getClassLoader() 动态代理类的类加载器  
            //rsd.getClass().getInterfaces() 代理类要实现的接口列表  
            //handler 指派方法调用的调用处理程序  
            SubjectDemo sd = (SubjectDemo)Proxy.newProxyInstance(classType.getClassLoader(), rsd.getClass().getInterfaces(), handler ) ;  
              
            //这行代码一执行 转到 InvocationHandler handler = new DynamicProxySubjectDemo(rsd)  
             //执行invoke方法  
            sd.request() ;  
        }  
    } 
  • 相关阅读:
    NGINX proxy_pass 域名解析问题
    NGINX源码分析——概览
    NGINX源代码自我总结(一)
    XWindow、Server、Client和QT、GTK之间的关系
    UBUNTU 字符界面来回切换
    ECshop 数据库表结构
    通读Cheerio文档
    Node.js 0.12: 正确发送HTTP POST请求
    npm配置镜像、设置代理
    配置 Windows 下的 nodejs C++ 模块编译环境 安装 node-gyp
  • 原文地址:https://www.cnblogs.com/LeshengW/p/10722509.html
Copyright © 2011-2022 走看看