day24XML、工厂模式、装饰模式

XML

在这里插入图片描述

XML eXtensible Markup Language 可扩展的标记语言
它是一种数据的表示格式,可用来表示结构复杂的数据
常用于数据的存储和传输

XML的几个特点和使用场景
一是纯文本,默认使用UTF-8编码;二是可嵌套;
如果把XML内容存为文件,那么它就是一个XML文件。
XML的使用场景:XML内容经常被当成消息进行网络传输,或者作为配置文件用于存储系统的信息。

XML的语法规则

XML的创建
创建一个xml文件
语法规则:
第一行必须是文档声明
标签(元素)规则
标签由一对尖括号和合法标识符组成: ,必须存在一个根标签,有且只能有一个。
标签必须成对出现,有开始,有结束:
特殊的标签可以不成对,但是必须有结束标记,如:

标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来
XML的其他组成
XML文件中可以定义注释信息:<!– 注释内容 -->
XML文件中可以存在以下特殊字符

在这里插入图片描述
XML文件中可以存在CDATA区: <![CDATA[ …内容… ]]>

以下是xml案例

<?xml version="1.0" encoding="UTF-8" ?>
<!--文档声明必须在第一行-->
<!-- 这是一条注释信息 -->
<!-- 必须要有root标签有且只有一条 -->
<student>
    <name>张无忌</name>
    <age>16</age>
    <hobby>练武功</hobby>
    <info id = "1">
        <address>武当山</address>
        <sex></sex>
    </info >
    <sql>
<!--    特殊字符与标识符冲突的如:<    -->
        select * form student where age &lt; 18;
    </sql>
    <!--CDATA区域可以随便写内容 快捷键CD-->
    <![CDATA[
        撒旦放假啦附件
        的房价就
        select * from user where name = "张三";
    ]]>
</student>

文档约束

问题:由于XML是可以扩展的 标签可以自己定义。在解析时就可能不知道有哪些标签,所以需要加以约束

什么是文档约束(了解)

就是限定了xml文件中的标签及其属性如何书写
从而强制约束程序员必须按照文档约束的规定来编写xml文件。
文档约束分为两类:
DTD
schema

DTD
新建一个dtd文件格式如下

<!ELEMENT 书架 (+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>

通过 导入DTD约束
根据约束编写xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "data.dtd">
<书架>
    <>
        <书名> 天龙八部  </书名>
        <作者>金庸</作者>
        <售价>99</售价>
    </>
    <>
        <书名>金瓶梅</书名>
        <作者>佚名</作者>
        <售价>很贵</售价>
    </>
</书架>

DTD约束成功限制了xml的编写格式但也存在问题
它不能限制具体的类型
如将金瓶梅的售价改成 很贵 显然是不合理的

文档约束-schema(了解如何使用)

  • schema可以约束具体的数据类型,约束能力上更强大。
  • schema本身也是一个xml文件,本身也受到其他约束文件的要求,所以编写的更加严谨 在这里插入图片描述
    schema通常由其他人写好只需调用并按照其格式编写即可

Sechema文件:hello_world_schema.xml

<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.itcast.cn"
        elementFormDefault="qualified" >
    <!-- targetNamespace:申明约束文档的地址(命名空间)-->
    <element name='书架'>
        <!-- 写子元素 -->
        <complexType>
            <!-- maxOccurs='unbounded': 书架下的子元素可以有任意多个!-->
            <sequence maxOccurs='unbounded'>
                <element name='书'>
                    <!-- 写子元素 -->
                    <complexType>
                        <sequence>
                            <element name='书名' type='string'/>
                            <element name='作者' type='string'/>
                            <element name='售价' type='double'/>
                        </sequence>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>

导入Schema文件按照其格式编码

<?xml version="1.0" encoding="UTF-8" ?>
<书架 xmlns="http://www.itcast.cn"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.itcast.cn data.xsd">
    <!-- xmlns="http://www.itcast.cn"  基本位置
         xsi:schemaLocation="http://www.itcast.cn books02.xsd" 具体的位置 -->
    <>
        <书名>神雕侠侣</书名>
        <作者>金庸</作者>
        <售价>399.9</售价>
    </>
    <>
        <书名>神雕侠侣</书名>
        <作者>金庸</作者>
        <售价>19.5</售价>
    </>

</书架>

XML解析

XML是用来存储数据、做配置文件、进行数据传输的
最终是要被程序读取并解析出内容

什么是XML解析?
使用程序解析出XML中的数据
常用的解析方式:
SAX解析
DOM解析 是常用的解析方式

Dom常见的解析工具

重点掌握dom4j

百度dom4j
download 三个文件
dom4j.jar是核心jar包
dom4j.source是源代码
dom4j.javadoc是API文档

这里的id是标签的属性
解析结构在这里插入图片描述

XML解析的步骤
下载Dom4j框架,官网下载。
在项目中创建一个文件夹:lib
将dom4j-2.1.1.jar文件复制到 lib 文件夹
在jar文件上点右键,选择 Add as Library -> 点击OK
在类中导包使用
解析后的元素对象都时实现了Node接口的子类

    public void parseXML() throws Exception {
        //1.创建一个SAXReader解析器
        SAXReader saxReader = new SAXReader();

        //2.把XMl文件加载到内存中成为一个Document文档对象
        //都需要通过模块名去定位
//        Document document = saxReader.read(new File("my-xml-app/src/Contacts.xml"));
//        Document document1 = saxReader.read(new FileInputStream("my-xml-app/src/Contacts.xml\""));
        //通过Class 中的getResourceAsStream 接口 使用文件名定位src目录下的文件
        InputStream is = HelloWorldDom4j.class.getResourceAsStream("Contacts.xml");

        Document document = saxReader.read(is); //
        //3.返回根对象
        Element root = document.getRootElement();
        System.out.println(root.getName());
        //4.通过根对象得到子元素
        List<Element> elements = root.elements();
        for (Element element : elements) {
            System.out.println(element.getName());
        }
        //拿某个子元素
        Element userEle = root.element("user");
        System.out.println(userEle.getName());
        //名字重复默认取第一个元素
        Element contactEle = root.element("contact");
        System.out.println(contactEle.getName());
        //获取子元素文本
//        System.out.println(contactEle.getText());// contact没有文本打印出与其行数相等的空行
//        System.out.println(1);
        System.out.println(contactEle.elementText("id"));
        System.out.println(contactEle.elementText("name"));
        System.out.println(contactEle.elementTextTrim("name"));


    }

XPath检索

package com.myself.xpath;

import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import java.util.List;

/**
 目标:XPath检索XML中的信息啊。(了解)

 引入:
 Dom4J可以用于解析整个XML的数据。
 但是如果要检索XML中的某些信息,建议使用XPath.(Xpath依赖Dom4j技术)
 Dom4J用于解析数据,Xpath用于检索数据。
 XPath使用步骤:
 1.导入dom4j框架。(XPath依赖于Dom4j技术,必须先导入dom4j框架!)
 2.导入XPath独有的框架包。jaxen-1.1.2.jar
 XPath常用API:
 List<Node> selectNodes(String var1):检索出一批节点集合。
 Node selectSingleNode(String var1):检索出一个节点返回。
 XPath提供的四种检索数据的写法:
 1.绝对路径。
 2.相对路径。
 3.全文搜索。
 4.属性查找。
 小结:
 1.绝对路径: /根元素/子元素/子元素。
 2.相对路径: ./子元素/子元素。 (.代表了当前元素)
 3.全文搜索:
 //元素  在全文找这个元素
 //元素1/元素2  在全文找元素1下面的一级元素2
 //元素1//元素2  在全文找元素1下面的全部元素2
 4.属性查找。
 //@属性名称  在全文检索属性对象。
 //元素[@属性名称]  在全文检索包含该属性的元素对象。
 //元素[@属性名称=值]  在全文检索包含该属性的元素且属性值为该值的元素对象。
 */
public class E1XPath {

    //一、绝对路径 /根元素/子元素/子元素
    @Test
    public  void parse01() throws Exception {
        //1.获取解析器对象
        SAXReader saxReader = new SAXReader();
        //2.获取文件对象
        Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts.xml"));
        //3.检索节点 根据绝对路径
        List<Node> nodesEle = document.selectNodes("/contactList/contact/name");
        //4.遍历节点
        for (Node nodeEle : nodesEle) {
            //强制转换为Element类型
            Element ele = (Element) nodeEle;
            System.out.println(ele.getTextTrim());
        }
    }
    //相对路径
    @Test
    public void parse02() throws Exception {
        //1.获取解析器对象
        SAXReader saxReader = new SAXReader();
        //2.获取文件对象
        Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts.xml"));
        //3.获取根元素
        Element root = document.getRootElement();
        //4.检索节点,根据根元素 这里的 . 代表当前元素
        List<Node> nodesEle = root.selectNodes("./contact/name");
        //5.遍历节点
        for (Node nodeEle : nodesEle) {
            //强制转换为Element类型
            Element ele = (Element) nodeEle;
            System.out.println(ele.getTextTrim());
        }
    }
    //全文检索
    //元素  在全文document找这个元素
    //元素1/元素2  在全文找元素1下面的一级元素2
    //元素1//元素2  在全文找元素1下面的全部元素2
    @Test
    public void parse03() throws Exception {
        //1.获取解析器对象
        SAXReader saxReader = new SAXReader();
        //2.获取文件对象
        Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts2.xml"));
        //3.获取根元素
        Element root = document.getRootElement();
        //4.检索节点,根据根元素 这里的 . 代表当前元素

      //  List<Node> nodesEle = document.selectNodes("//name");
        //List<Node> nodesEle = document.selectNodes("//contact/name");
        List<Node> nodesEle = document.selectNodes("//contact//name");
                //5.遍历节点
        for (Node nodeEle : nodesEle) {
            //强制转换为Element类型
            Element ele = (Element) nodeEle;
            System.out.println(ele.getTextTrim());
        }
    }
    //4.属性查找。
    //  1.  //@属性名称  在全文检索属性对象。
    //  2.  //元素[@属性名称]  在全文检索包含该属性的元素对象。
    //  3.  //元素[@属性名称=值]  在全文检索包含该属性的元素且属性值为该值的元素对象。
    @Test
    public void parse04() throws Exception{
        //1.获取解析器对象
        SAXReader saxReader = new SAXReader();
        //2.获取Document文件对象
        Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts2.xml"));
        //3.检索数据
        //查询所有的id属性
        //List<Node> nodesEle = document.selectNodes("//@id");
        List<Node> nodesEle = document.selectNodes("//name[@id]");

//        for (Node nodeEle : nodesEle) {
//            //强制转换为Attribute类型
//            Attribute ele = (Attribute) nodeEle;
//            System.out.println(ele.getName() + ele.getValue());
//        }
        for (Node nodeEle : nodesEle) {
            //强制转换为Attribute类型
            Element ele = (Element) nodeEle;
            System.out.println(ele.getName() + ele.getTextTrim());
        }
        //得到单个Node对象
        Node node = document.selectSingleNode("//name[@id = 888]");
        System.out.println(node.getName() + node.getText());
    }
}

工厂设计模式

在业务场景之中,有时不能我们自己new一个对象,如computer类所有我们需要用的工厂来产生类
工厂模式(FactoryPattern)是一种常用的设计模式,是创造型设计模式,它提供了类的获取 方式

定义了一个电脑类
package com.itheima.d3_factory_pattern;

public abstract class Computer {
    private String name;
    private double price;

    public abstract void start();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

工厂类提供了方法返回Computer对象
public class FactoryPattern {
    /**
       定义一个方法,创建对象返回
     */
    public static Computer createComputer(String info){
        switch (info){
            case "huawei":
                Computer c = new Huawei();
                c.setName("huawei pro 16");
                c.setPrice(5999);
                return c;
            case "mac":
                Computer c2 = new Mac();
                c2.setName("MacBook pro");
                c2.setPrice(11999);
                return c2;
            default:
                return null;
        }
    }
}
/**
    目标:工厂模式。

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

    工厂设计模式的作用:
            1.对象通过工厂的方法创建返回,工厂的方法可以为该对象进行加工和数据注入。
            2.可以实现类与类之间的解耦操作(核心思想,重点)
            这样测试类与类之间的联系变少,只需要更新维护工厂类就可以

    小结:
        工厂模式的思想是提供一个工厂方法返回对象!
 */
public class FactoryDemo {
    public static void main(String[] args) {
        Computer c1 = FactoryPattern.createComputer("huawei");
        c1.start();

        Computer c2 = FactoryPattern.createComputer("mac");
        c2.start();
    }
}

装饰模式

什么是装饰类?
创建一个新类继承父类
在不改变原类的基础之上动态的扩展一个类的功能

定义父类。
定义原始类,继承父类,定义功能。
定义装饰类,继承父类,包装原始类,增强功能!!


/**
   共同父类
 */
public abstract class InputStream {
    public abstract int read();
    public abstract int read(byte[] buffer);
}

package com.itheima.d4_decorator_pattern;

import java.util.Arrays;

/**
   原始类
 */
public class FileInputStream extends InputStream{
    @Override
    public int read() {
        System.out.println("低性能的方式读取了一个字节a");
        return 97;
    }

    @Override
    public int read(byte[] buffer) {
        buffer[0] = 97;
        buffer[1] = 98;
        buffer[2] = 99;
        System.out.println("低性能的方式读取了一个字节数组:" + Arrays.toString(buffer));
        return 3;
    }
}

/**
   装饰类:继承InputStream 拓展原始类的功能
 */
public class BufferedInputStream extends InputStream{
    private InputStream is;
    public BufferedInputStream(InputStream is){
        this.is = is;
    }
    @Override
    public int read() {
        System.out.println("提供8KB的缓冲区,提高读数据性能~~~~");
        return is.read();
    }

    @Override
    public int read(byte[] buffer) {
        System.out.println("提供8KB的缓冲区,提高读数据性能~~~~");
        return is.read(buffer);
    }
}
/**
  装饰模式

    定义父类:InputStream
    定义实现类:FileInputStream 继续父类 定义功能
    定义装饰实现类:BufferedInputStream 继承父类 定义功能 包装原始类,增强功能。
 */
public class DecoratorPattern {
    public static void main(String[] args) {
        InputStream is = new BufferedInputStream(new FileInputStream());
        System.out.println(is.read());
        System.out.println(is.read(new byte[3]));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值