JavaSE(Dom4j、单例设计模式、多例设计模式、动态代理、工厂设计模式)

Dom4j

XML解析

解析方式

  • 开发中比较常见的解析方式有三种,如下:

    1. DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象

      a)优点:元素与元素之间保留结构关系,故可以进行增删改查操作。

      b)缺点:XML文档过大,可能出现内存溢出

    2. SAX:是一种速度更快,更有效的方法。她逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都触发对应的事件。(了解)

      a)优点:不会出现内存问题,可以处理大文件

      b)缺点:只能读,不能回写。

    3. PULL:Android内置的XML解析方式,类似SAX。(了解)

  • 解析器,就是根据不同的解析方式提供具体实现。有的解析器操作过于繁琐,为了方便开发人员,有提供易于操作的解析开发包
    在这里插入图片描述

解析包

  • JAXP:sun公司提供支持DOM和SAX开发包
  • Dom4j: 比较简单的的解析开发包(常用)
  • JDom:与Dom4j类似
  • Jsoup:功能强大DOM方式的XML解析开发包,尤其对HTML解析更加方便

Dom4j的基本使用

DOM解析原理及结构模型

  • 解析原理
    XML DOM 和 HTML DOM一样,XML DOM 将整个XML文档加载到内存,生成一个DOM树,并获得一个Document对象,通过Document对象就可以对DOM进行操作。以下面books.xml文档为例。
    <?xml version="1.0" encoding="UTF-8"?>
    <books>
        <book id="0001">
            <name>xxx</name>
            <author>xxx</author>
            <sale>100.00元</sale>
        </book>
        <book id="0002">
            <name>xxxx</name>
            <author>xxxx</author>
            <sale>100.00元</sale>
        </book>
    </books>
    
  • 结构模型
    在这里插入图片描述
    DOM中的核心概念就是节点,在XML文档中的元素、属性、文本,在DOM中都是节点!所有的节点都封装到了Document对象中。

使用步骤

  1. 导入jar包 dom4j-1.6.1j.jar
  2. 创建解析器
  3. 读取xml 获得document对象
  4. 得到根元素
  5. 根据根元素获取对于的子元素或者属性

常用的方法

创建解析器对象:
	SAXReader sr = new SAXReader();
解析器读取文件方法:
	Document doc = sr.read(String fileName);
Document的方法:
	getRootElement()			: 获取根元素	
	
节点中的方法:	
	elements()     				: 获取当前元素的子元素
	element(String name)		: 根据元素名获取指定子元素(如果有多个就获取到第一个)
	getName()					: 获取元素的元素名
    elementText(String name)	: 获取指定子元素的文本值,参数是子元素名称
	attributeValue(String name)	: 获取当前元素下某个属性的值
	getText()					: 获取当前元素的文本值

方法演示

  • xml
    <?xml version="1.0" encoding="UTF-8"?>
    
    <天气预报>
        <北京 provide='' id='1'>
            <温度>
                <最高温度 level="A">18</最高温度>
                <最低温度>6</最低温度>
            </温度>
            <湿度>20%</湿度>
        </北京>
    
        <深圳>
            <温度>
                <最高温度 level="C">36</最高温度>
                <最低温度>24</最低温度>
            </温度>
            <湿度>50%</湿度>
        </深圳>
    	
    	 <广州>
    		<温度>
                <最高温度 level="C">32</最高温度>
                <最低温度>21</最低温度>
            </温度>
            <湿度>50%</湿度>
    		
    		<黄浦区>
    			<温度>
    				<最高温度 level="C">31</最高温度>
    				<最低温度>22</最低温度>
    			</温度>
    			<湿度>50%</湿度>
    		</黄浦区>
    		
    		<天河区>
    			<温度>
    				<最高温度 level="C">30</最高温度>
    				<最低温度>26</最低温度>
    			</温度>
    			<湿度>50%</湿度>
    		</天河区>
        </广州>
    </天气预报>
    
  • 解析
public class Test {
    public static void main(String[] args) throws Exception {
        
        // 创建解析器对象
        SAXReader sr = new SAXReader();

        // 使用解析器解析xml文件,生成document对象
        Document document = sr.read("a/tianqi.xml");

        // 使用document对象获得根元素
        Element rootE = document.getRootElement();
        System.out.println(rootE);

        // elements()     				: 获取当前元素的所有子元素
        // 获取根元素下的所有子元素
        List<Element> eList = rootE.elements();
        System.out.println("根元素下子元素的个数:"+eList.size());// 3

        // 遍历根元素下的所有子元素 的名称
        for (Element e : eList) {
            // getName()					: 获取元素的元素名
            System.out.println(e.getName());
        }

        System.out.println("=======================");
        // element(String name)		: 根据元素名获取指定子元素(如果有多个就获取到第一个)
        // 获取根元素下的北京子元素
        Element e1 = rootE.element("北京");
        System.out.println(e1.getName());// 北京

        System.out.println("====================");
        // 获取北京下的子元素湿度的文本
        // elementText(String name)	: 获取指定子元素的文本值,参数是子元素名称
        System.out.println(e1.elementText("湿度"));// 20%

        System.out.println("====================");

        // getText()					: 获取当前元素的文本值
        // 获取北京下的子元素湿度
        Element e2 = e1.element("湿度");
        System.out.println(e2.getText());// 20%

        System.out.println("====================");
        // attributeValue(String name)	: 获取当前元素下某个属性的值
        // 获取北京元素的provide属性的值
        System.out.println(e1.attributeValue("provide"));// 京

    }
}

Dom4J结合XPath解析XML

介绍

XPath 使用路径表达式来选取HTML\XML 文档中的元素节点或属性节点。节点是通过沿着路径 (path) 来选取的。XPath在解析HTML\XML文档方面提供了独树一帜的路径思想。

XPath使用步骤

步骤1:导入jar包(dom4j和jaxen-1.1-beta-6.jar)

步骤2:通过dom4j的SaxReader解析器对象,获取Document对象

步骤3: 利用Xpath提供的api,结合xpaht的语法完成选取XML文档元素节点进行解析操作。

document常用的api

  • document.selectSingleNode(“xpath语法”); 获得一个节点(标签,元素)
  • document.selectNodes(“xpath语法”); 获得多个节点(标签,元素)

XPath语法(了解)

  • XPath表达式,就是用于选取HTML文档中节点的表达式字符串。
    获取XML文档节点元素一共有如下4种XPath语法方式:

    1. 绝对路径表达式方式 例如: /元素/子元素/子子元素…
    2. 相对路径表达式方式 例如: 子元素/子子元素… 或者 ./子元素/子子元素…
    3. 全文搜索路径表达式方式 例如: //子元素//子子元素
    4. 谓语(条件筛选)方式 例如: //元素[@attr1=value]
  • 获取不同节点语法

    获取类型语法代码
    获取元素节点元素名称
    获取属性节点@属性名称
绝对路径表达式(了解)
  • 绝对路径介绍

  • 以/开头的路径叫做是绝对路径,绝对路径要从根元素开始写

  • public class Test {
        public static void main(String[] args)throws Exception {
            /*
                - document.selectSingleNode("xpath语法");   获得一个节点(标签,元素)
                - document.selectNodes("xpath语法");      获得多个节点(标签,元素)
             */
            // 创建解析器
            SAXReader sr = new SAXReader();
            // 读取xml 获得document对象
            Document document = sr.read("a/src/tianqi.xml");
            // 得到根元素
            Element rootE = document.getRootElement();
            System.out.println(rootE);
    
            // 绝对路径: 获取深圳 湿度
            Node node = rootE.selectSingleNode("/天气预报/深圳/湿度");
            System.out.println(node.getName());// 湿度
            System.out.println(node.getText());// 50%
    
        }
    }
    
相对路径表达式(了解)
  • 相对路径介绍
    • 相对路径就是相对当前节点元素位置继续查找节点,不以/开头, …/ 表示上一个元素, ./表示当前元素

      public class Test {
          public static void main(String[] args)throws Exception {
            /*
                  - document.selectSingleNode("xpath语法");   获得一个节点(标签,元素)
                  - document.selectNodes("xpath语法");      获得多个节点(标签,元素)
               */
              // 创建解析器
              SAXReader sr = new SAXReader();
              // 读取xml 获得document对象
              Document document = sr.read("a/src/tianqi.xml");
              // 得到根元素
              Element rootE = document.getRootElement();
              System.out.println(rootE);
      
              // 相对路径: 获取深圳 湿度
              Node node = rootE.selectSingleNode("./深圳/湿度");
              System.out.println(node.getName());// 湿度
              System.out.println(node.getText());// 50%
      
      
              //用绝对路径的方式获取“温度”
              Node node2 = document.selectSingleNode("/天气预报/北京/温度");
              // 相对路径: 获取北京 湿度
              Node node3 = node2.selectSingleNode("../湿度");
              System.out.println(node3.getName());// 湿度
              System.out.println(node3.getText());// 20%
      
          }
      }
      
全文搜索路径表达式(了解)
  • 全文搜索路径介绍

    • 代表不论中间有多少层,直接获取所有子元素中满足条件的元素

      public class Test {
          public static void main(String[] args)throws Exception {
              /*
                  - document.selectSingleNode("xpath语法");   获得一个节点(标签,元素)
                  - document.selectNodes("xpath语法");      获得多个节点(标签,元素)
               */
              // 创建解析器
              SAXReader sr = new SAXReader();
              // 读取xml 获得document对象
              Document document = sr.read("a/src/tianqi.xml");
              // 得到根元素
              Element rootE = document.getRootElement();
              System.out.println(rootE);
      
              // 获取天气预报里的所有湿度,不论有多少层
              List<Element> list = rootE.selectNodes("//湿度");
              for (Element e : list) {
                  System.out.println(e.getName()+","+e.getText());
              }
          }
      }
      
谓语(条件筛选 了解)
  • 介绍
    谓语,又称为条件筛选方式,就是根据条件过滤判断进行选取节点

  • 格式:
    ​String xpath1="//元素[@attr1=value]";//获取元素属性attr1=value的元素

    ​String xpath2="//元素[@attr1>value]/@attr1"//获取元素属性attr1>value的d的所有attr1的值

    String xpath3="//元素[@attr1=value]/text()";//获取符合条件元素体的自有文本数据

    String xpath4="//元素[@attr1=value]/html()";//获取符合条件元素体的自有html代码数据。

    ​String xpath3="//元素[@attr1=value]/allText()";//获取符合条件元素体的所有文本数据(包含子元素里面的文本)

演示

public class Test {
    public static void main(String[] args)throws Exception {
        /*
            - document.selectSingleNode("xpath语法");   获得一个节点(标签,元素)
            - document.selectNodes("xpath语法");      获得多个节点(标签,元素)
         */
        // 创建解析器
        SAXReader sr = new SAXReader();
        // 读取xml 获得document对象
        Document document = sr.read("a/src/tianqi.xml");
        // 得到根元素
        Element rootE = document.getRootElement();
        System.out.println(rootE);

        // 获取最高温度中属性名是level 属性值是A的元素
        List<Element> list = rootE.selectNodes("//最高温度[@level='C']");
        for (Element e : list) {
            System.out.println(e.getName()+","+e.getText());
        }
    }
}

单例设计模式

单例设计模式的概述

单例设计模式的作用

单例模式,是一种常用的软件设计模式。通过单例模式可以保证系统中,应用该模式的这个类只有一个实例。即一个类只有一个对象实例。

单例设计模式实现步骤

  1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在该类内部产生一个唯一的实例化对象
  3. 定义一个静态方法返回这个唯一对象。

单例设计模式的类型

根据实例化对象的时机单例设计模式又分为以下两种:

  1. 饿汉单例设计模式
  2. 懒汉单例设计模式

饿汉式单例设计模式

饿汉单例设计模式就是使用类的时候已经将对象创建完毕,不管以后会不会使用到该实例化对象,先创建了再说。很着急的样子,故被称为“饿汉模式”。

代码如下:

public class Person {
    // 使用饿汉式单例设计模式: 比较着急,不管要不要获取我这个类的对象,先创建了该对象再说
    // 1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Person(){
    }

    // 2. 在该类内部产生一个唯一的实例化对象
    private static final Person p = new Person();

    // 3. 定义一个静态方法返回这个唯一对象。
    public static Person getInstance(){
        return p;
    }

    // ....
}

public class Test {
    public static void main(String[] args) {
        Person p1 = Person.getInstance();
        Person p2 = Person.getInstance();
        Person p3 = Person.getInstance();

        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p3);

    }
}

懒汉式单例设计模式

懒汉单例设计模式就是调用getInstance()方法时实例才被创建,先不急着实例化出对象,等要用的时候才实例化出对象。不着急,故称为“懒汉模式”。

代码如下:

public class Person {
    // 懒汉式单例: 不着急,只要当你调用了getInstance静态方法获取对象的时候,就创建,其他时候不创建
    // 1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Person(){

    }

    // 2. 在该类内部产生一个唯一的实例化对象
    private static Person p ;// 默认值为null

    // 3. 定义一个静态方法返回这个唯一对象。
    public static synchronized Person getInstance(){
        // 创建Person类的唯一对象
        // 判断一下,如果p这个成语变量的值为null,就创建,不为null,说明该对象已经创建了,直接返回即可
        if (p == null){
            p = new Person();
        }
        return p;
    }

    // ...
}

public class Test {
    public static void main(String[] args) {
        Person p1 = Person.getInstance();
        Person p2 = Person.getInstance();
        Person p3 = Person.getInstance();

        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p3);

    }
}

注意:懒汉单例设计模式在多线程环境下可能会实例化出多个对象,不能保证单例的状态,所以加上关键字:synchronized,保证其同步安全。

多例设计模式

多例设计模式

多例设计模式的作用

多例模式,是一种常用的软件设计模式。通过多例模式可以保证系统中,应用该模式的类有固定数量的实例。多例类要自我创建并管理自己的实例,还要向外界提供获取本类实例的方法。

实现步骤

​ 1.创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
​ 2.在该类内部产生固定数量的实例化对象 ----> 集合
​ 3.提高一个静态方法来随机获取一个该了的实例化对象

实现代码

public class Person {
    // 使用多例设计模式: 保证程序运行期间该类只有固定数量的对象产生
    // 1.创建一个类,  将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Person(){
    }

    // 2.在该类内部产生固定数量的实例化对象 ----> 集合  只能产生依次固定数量的对象

    // 2.1 定义一个存放该类对象的集合
    private static ArrayList<Person> list = new ArrayList<>();

    // 2.2 在静态代码块中,创建固定数量的对象,添加到集合中
    static {
        // 创建固定数量的该类对象
        for (int i = 0; i < 3; i++) {
            Person p = new Person();
            list.add(p);
        }
    }

    // 3.提高一个静态方法来随机获取一个该了的实例化对象
    public static Person getInstance(){
        // 创建一个Random对象
        Random r = new Random();
        // 随机产生一个list集合的索引
        int index = r.nextInt(list.size());// [0,3) 0,1,2
        // 根据索引获取对象
        Person p = list.get(index);
        // 返回对象
        return p;
    }
}

测试结果

public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Person p1 = Person.getInstance();
            System.out.println(p1);
        }
    }
}

在这里插入图片描述

动态代理

代理模式概述

为什么要有“代理”?生活中就有很多代理的例子,例如,我现在需要出国,但是我不愿意自己去办签证、预定机票和酒店(觉得麻烦 ,那么就可以找旅行社去帮我办,这时候旅行社就是代理,而我自己就是被代理了。

代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者, 所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议)

静态代理:

public interface Happy {// 协议,被代理者需要代理的方法,就定义在这里,然后让代理者和被代理者去实现
    // 被代理者实现: 为了确保和代理者实现的方法一致
    // 代理者实现: 为了增强被代理者的这些方法
    public abstract void happy();
}


public class XiaoMing implements Happy {

    public void happy(){
        System.out.println("小明在happy...");
    }

}


public class XiaoHei implements Happy{
    // 成员变量
    XiaoMing xm;

    // 构造方法
    public XiaoHei(XiaoMing xm) {
        this.xm = xm;
    }

    // 成员方法
    @Override
    public void happy() {
        System.out.println("小黑约了ktv...");
        // 小明happy
        xm.happy();
        System.out.println("小黑结账...");
    }
}


public class 小白 {
    public static void main(String[] args) {
        /*
            案例: 小明要找小白happy
            代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者,
            所以代理模式包含了3个角色: 被代理角色     代理角色    抽象角色(协议)

         */
        // 不请代理: 小明直接找小白happy
        // 创建小明对象
        XiaoMing xm = new XiaoMing();
        // happy
        // xm.happy();

        // 请代理: 静态代理,代理类真实存在
        Happy xh = new XiaoHei(xm);// wp:代理对象   XiaoHei类: 代理类   Happy接口: 协议  XiaoMing: 被代理类
        xh.happy();
    }
}

动态代理介绍

  • 概述 : 动态代理就是直接通过反射生成一个代理对象,代理对象所属的类是不需要存在的

  • 动态代理的获取:
    ​jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象

动态代理相关api介绍

Java.lang.reflect.Proxy类可以直接生成一个代理对象

  • Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
    • 参数1:ClassLoader loader 被代理对象的类加载器
    • 参数2:Class<?>[] interfaces 被代理对象的要实现的接口
    • 参数3:InvocationHandler h (接口)执行处理类
    • 返回值: 代理对象
    • 前2个参数是为了帮助在jvm内部生成被代理对象的代理对象,第3个参数,用来监听代理对象调用方法,帮助我们调用方法
  • InvocationHandler中的Object invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行
    • 参数1:代理对象(慎用)
    • 参数2:当前执行的方法
    • 参数3:当前执行的方法运行时传递过来的参数
    • 返回值:当前方法执行的返回值

工厂设计模式

工厂模式的介绍

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。之前我们创建类对象时, 都是使用new 对象的形式创建, 除new 对象方式以外, 工厂模式也可以创建对象。

耦合度: 类与类之间的关系,如果关系比较强,高耦合, 如果关系比较弱,低耦合

10个类:

测试类: 创建这10个类的对象

以前: 直接通过new 来创建 测试类和10个类关系起来

工厂模式: 定义一个类,专门用来创建这10个类的对象, 并提供获取的方法,那这个时候测试类只需要跟测试类关联 低耦合

工厂模式的作用

将前端代码与要创建的对象分开,前端不需要直接创建对象,也就不需要关心创建对象时需要的数据。只需要通过工厂获取对象即可。

  • 解决类与类之间的耦合问题

案例演示

需求

  1. 编写一个Car接口, 提供run方法
  2. 编写一个Falali类实现Car接口,重写run方法
  3. 编写一个Benchi类实现Car接口,重写run方法

提供一个工厂类,可以用来生产汽车对象

实现代码

1.编写一个Car接口, 提供run方法

public interface Car {
    public void run();
}

2.编写一个Falali类实现Car接口,重写run方法

public class Falali implements Car {
    @Override
    public void run() {
        System.out.println("法拉利以每小时500公里的速度在奔跑.....");
    }
}

3.编写一个Benchi类实现Car接口

public class Benchi implements Car {
    @Override
    public void run() {
        System.out.println("奔驰汽车以每秒1米的速度在挪动.....");
    }
}

4.提供一个CarFactory(汽车工厂),用于生产汽车对象

public class CarFactory {
    /**
     * @param id : 车的标识
     *           benchi : 代表需要创建Benchi类对象
     *           falali : 代表需要创建Falali类对象
     *           如果传入的车标识不正确,代表当前工厂生成不了当前车对象,则返回null
     * @return
     */
    public Car createCar(String id){
        if("falali".equals(id)){
            return new Falali();
        }else if("benchi".equals(id)){
            return new Benchi();
        }
        return null;
    }
}

5.定义CarFactoryTest测试汽车工厂

public class CarFactoryTest {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        Car benchi = carFactory.createCar("benchi");
        benchi.run();
        Car falali = carFactory.createCar("falali");
        falali.run();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值