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() ;  
        }  
    } 
  • 相关阅读:
    PHP 大小写转换、首字母大写、每个单词首字母大写转换相关函数
    【论文学习4】BiSample: Bidirectional Sampling for Handling Missing Data with Local Differential Privacy
    【论文学习3】Local Differential Privacy for Deep Learning
    【论文学习2】 Differential Privacy Reinforcement Learning
    深度学习中的优化算法
    Spatial crowdsourcing
    “pip install tensorflow ”出现错误
    python或pip'不是内部或外部命令”
    pip install torch出现错误
    打不开gitHub的解决方法
  • 原文地址:https://www.cnblogs.com/bbeb/p/10707213.html
Copyright © 2011-2022 走看看