3/31day23_设计模式

2020-04-03  本文已影响0人  蹦蹦跶跶的起床啊

复习

SAXReader read方法  
    public class TestDemo {
    public static void main(String[] args) throws DocumentException {
        SAXReader reader = new SAXReader();
        // 根目录下的books.xml
        Document document1 = reader.read(new File("books.xml")); 
        //根目录下day23模块下的books.xml
        Document document2 = reader.read(new File("day23/books.xml"));
        //在src下的books.xml
        InputStream in = TestDemo.class.getResourceAsStream("/books.xml");
        Document document3 = reader.read(in); 
    }
}

1.XML语法
2.XML约束(DTD,Schema)
    我们重点是根据约束写出符合规则的文档(IDEA提示)
3.XML的解析
    a.直接解析
    SAXReader reader = new SAXReader();
    Document document = reader.read(new File("books.xml")); 
    Element rootElement = document.getRootElement();
    List<Element> elements = rootElement.elements();
    getName();//获取标签名
    getText();//获取标签内容
    attributeValue(String attrName);//获取标签某个属性值

    b.集合XPath
    List<Element> elements = selectNodes(String xpath);  
    Element element = selectSingleNode(String xpath);

今日内容

设计模式!【重点】
1.单例设计模式
2.多例设计模式
3.动态代理【超难,现在1次,web阶段1次,框架阶段1次】
今日目标: 把格式学会(怎么用)
4.工厂设计模式(解耦)
5.Lombok【自学】


day23

单例设计模式

单例设计模式介绍

单例设计模式的作用就是为了想让一个类只能有一个实例对象

单例设计模式的实现步骤

  1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static final类型的成员变量。(private为了不让外部访问,static因为是要让改变量变成静态的。因为返回唯一对象的方法是静态的。因为不用静态方法的话,外部不能创建对象,会访问不了实例方法)
  3. 定义一个静态方法返回这个唯一对象。

单例设计模式的类型

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

饿汉式单例设计模式

public class Singleton {
    // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Singleton() {}
 
    // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
    private static final Singleton instance = new Singleton();
    
    // 3.定义一个静态方法返回这个唯一对象。
    public static Singleton getInstance() {
        return instance;
    }
}

缺点: 容易造成内存浪费

懒汉式单例设计模式

注意

必须要对返回对象方法用 synchronized 修饰, 否则多线程访问时, 不能保证原子性的话, 会出现创建多个对象的情况

public class Singleton {
    // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Singleton() {}
 
    // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
    private static Singleton instance;
     
    // 3.定义一个静态方法返回这个唯一对象。要用的时候才例化出对象
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}        

上述代码会造成线程阻塞

懒汉式单例模式的优化, 加上volatile保证可见性, 和防止重排, 双重检验不会造成线程阻塞

public class Singleton {
    // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Singleton() {}
 
    // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
    private static volatile Singleton instance;

public static Singleton getInstance() {
        //采取双重检验, 把锁加在第二次检验上, 不会造成线程阻塞
        if(instance == null) {
            synchronized(Singleton.class){
                instance = new Singleton();
            }          
        }
        return instance;
    }
}

多例设计模式

多例设计模式的介绍

多例设计模式的实现步骤

  1. 私有化构造(不让别人可以正常创建对象)

  2. 在类内部创建一个private static修饰的集合, 用于保存我们自己创建的对象

  3. 使用静态代码块 static{} 向集合中添加指定个数的对象

  4. 通过一个public static 静态方法, 随机返回集合中的某个对象

多里设计模式的代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Multition {
    // 定义该类被创建的总数量
    private static final int maxCount = 3;
    // 定义存放类实例的list集合
    private static List instanceList = new ArrayList()
    // 构造方法私有化,不允许外界创建本类对象
    private Multition() {
    }
    static {
        // 创建本类的多个实例,并存放到list集合中
        for (int i = 0; i < maxCount; i++) {
            Multition multition = new Multition();
            instanceList.add(multition);
        }
    }
    // 给外界提供一个获取类对象的方法
    public static Multition getMultition(){
        Random random = new Random();
        // 生成一个随机数
        int i = random.nextInt(maxCount);
        // 从list集合中随机取出一个进行使用
        return (Multition)instanceList.get(i);
    }
}

动态代理

代理模式介绍

代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事.为了让保存用户的集合不会被用户进行直接的增删改操作, 在用户和保存信息集合之间增加一个集合的代理

静态代理入门案例

静态代理是指代理类ArrayListProxy在编译时期已经定义好了

代理类步骤:

  1. 和被代理类实现相同接口(List). 并且重写所有接口内的方法
  2. 代理类内保存被代理类对象.并且用private修饰
/**
 * 此类就是普通ArrayList类的代理
 */
//1.让代理对象实现被代理对象一样的接口,目的是让代理对象和被代理对象具有一样的方法
public class ArrayListProxy implements List<String>{
    //2.要在代理对象中保存一个被代理对象
    private ArrayList<String> list;

    public ArrayListProxy(ArrayList<String> list) {
        this.list = list;
    }

    //3.下面的一堆方法中,如果是不修改集合数据的方法,就调用list的方法
    //如果是修改集合的方法,直接抛出异常
    @Override
    public boolean add(String s) {
        //直接抛出异常
        throw new UnsupportedOperationException("不允许调用add方法");
    }
    @Override
    public String get(int index) {
        return list.get(index);
    }
    @Override
    public String set(int index, String element) {
        //直接抛出异常
        throw new UnsupportedOperationException("不允许调用set方法");
    }
    @Override
    public String remove(int index) {
        //直接抛出异常
        throw new UnsupportedOperationException("不允许调用remove方法");
    }
}

public class TestProxyDemo {
    public static void main(String[] args) {
        //1.创建一个ArrayList
        ArrayList<String> arr = new ArrayList<String>();
        //保存用户的信息
        arr.add("张三");
        arr.add("18");
        arr.add("北京中关村");
        arr.add("188888块");

        //2.要集合arr先交给代理对象
        List<String> list = getArrayListProxy(arr);

        //3.操作
//        list.add("李四");  抛出异常!
//        list.remove(1); 抛出异常!
//        list.set(1, "28"); 抛出异常!
        System.out.println(list.get(2)); //OK 正常操作
    }

    public static List<String> getArrayListProxy(ArrayList<String> arr) {
        //创建一个ArrayList的代理
        ArrayListProxy arrayListProxy = new ArrayListProxy(arr);
        //返回代理对象
        return arrayListProxy;
    }
}

动态代理概述

动态代理案例

java.util.Collections:操作集合的工具类
 
static <T> List<T> unmodifiableList(List<? extends T> list)
        返回指定列表的不可修改视图。
        此方法允许模块为用户提供对内部列表的“只读”访问。
        在返回的列表上执行的查询操作将“读完”指定的列表。
        试图修改返回的列表(不管是直接修改还是通过其迭代器进行修改)将导致抛出         
        UnsupportedOperationException:不支持操作异常
unmodifiableList作用:传递List接口,方法内部对List接口进行代理,返回一个被代理后的List接口
        对List进行代理之后,调用List接口的方法会被拦截
        如果使用的size,get方法,没有对集合进行修改,则允许执行
        如果使用的add,remove,set方法,对集合进行了修改,则抛出运行时异常

动态代理的重点类和方法

java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,这个类提供了一个静态方法来为一组接口的实现类动态地生成代理类及其对象。(这个类必须是为有接口的被代理类提供动态代理)

动态代理模拟的综合案例

模仿Collections中定义的动态代理方法unmodifiableList

public class DynamicProxy {
    public static void main(String[] args) {
        ArrayList<String> arr = new ArrayList<>();
        arr.add("小昧");
        arr.add("12");
        arr.add("唐人街");
        arr.add("爱跳");
        arr.add("爱吃");
        List<String> list = unmodifiableList(arr);
     //   list.add("dddd");
     //   list.set(2,"wwww");
        System.out.println(list.get(3));

    }

    public static List<String> unmodifiableList(List<String> arr) {
      List<String> list = (List<String>) Proxy.newProxyInstance(
                arr.getClass().getClassLoader(),
                arr.getClass().getInterfaces(),
                new InvocationHandler() {
                    //这个方法就是用来拦截真实对象方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String name = method.getName();
                        //拦截 add,set,remove开头的方法
                        if (name.startsWith("add")) {
                            throw new UnsupportedOperationException("add方法禁止访问");
                        }
                        if (name.startsWith("set")) {
                            throw new UnsupportedOperationException("set方法禁止访问");
                        }
                        if (name.startsWith("remove")) {
                            throw new UnsupportedOperationException("remove方法禁止访问");
                        }

                        //正常执行的查询方法
                        Object result = method.invoke(arr, args);
                        return result;
                    }
                });
      return list;
    }
    //集合工具类自带的unmodifiableList方法
    public static void method() {
        ArrayList<String> arr = new ArrayList<>();
        arr.add("小昧");
        arr.add("12");
        arr.add("唐人街");
        arr.add("爱跳");
        arr.add("爱吃");

        List<String> list = Collections.unmodifiableList(arr);
     // list.add("haha");
        System.out.println(list.get(3));
     // list.remove(2);
    }
}

动态代理的优缺点

Lombok

介绍

是个第三方jar包

Lombok通过增加一些“处理程序”,可以让java变得简洁、快速。

Lombok能以注解形式来简化java代码,提高开发效率。开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护。

Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。

工厂设计模式

工厂设计模式的概述

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

把创建对象的过程交给工厂执行, 只从工厂中获取对象即可.

工厂模式作用

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

工厂模式步骤

  1. 提供一个所有类的父类/接口,
  2. 令所有类都实现这个接口并且重写接口内的方法
  3. 提供一个专门生产这些实现类对象的类(称为工厂类)
  4. 在测试类中调用工厂类的生产实现类对象的方法

工厂模式代码实现

  1. 编写一个Car接口, 提供run方法
public interface Car {
    public void run();
}
  1. 编写一个Falali类实现Car接口,重写run方法
public class Falali implements Car {
    @Override
    public void run() {
        System.out.println("法拉利以每小时500公里的速度在奔跑.....");
    }
}
  1. 编写一个Benchi类实现Car接口
public class Benchi implements Car {
    @Override
    public void run() {
        System.out.println("奔驰汽车以每秒1米的速度在挪动.....");
    }
}
  1. 提供一个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;
    }
}
  1. 定义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();
    }
}

可以使用配置文件达到0耦合

car.properties
id=3
       
public class TestCar {
    public static void main(String[] args) throws IOException {
        //0.从配置文件去读id
        Properties ps = new Properties();
        //加载配置文件
        ps.load(new FileInputStream("day23/car.properties"));
        //取出数据
        String id = ps.getProperty("id");
        //转成int
        int ID = Integer.parseInt(id);
        //1.创建一辆汽车 高耦合  低耦合
        Car aCar = CarFactory.getACar(ID);
        aCar.run();
    }
}   

今日总结

上一篇 下一篇

猜你喜欢

热点阅读