day23【设计模式】、单例设计模式、 多例设计模式、代理模式、动态代理、工厂设计模式

day23【设计模式】

反馈和复习
1.File[读音:fail]
2.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【自学】      

第一章 单例设计模式【重点】

1. 单例设计模式介绍
a.正常情况下一个类可以创建多个对象
b.单例设计模式作用就是让某个类只能有一个对象    
2. 单例设计模式实现步骤
a.将构造方法私有化(不让别人直接new对象)
b.在该类内部产生一个唯一的实例化对象,并且使用private static修饰 
c.提供一个public staic 的静态方法,该方法返回这个静态对象    
3 单例设计模式的类型
懒汉式:
	不立即创建本类的对象,当别人调用静态方法获取本类的对象时,才去创建
饿汉式: 
	先把对象创建出来,当别人调用静态方法获取本类的对象时,直接返回对象即可
4, 饿汉单例设计模式
/**
 * 要求Dog类采用单例模式中的饿汉式
 */
public class Dog {

    //3.提供一个静态方法,获取dd对象
    public static Dog getInstance(){
        return dd;
    }

    //2.自己定义一个对象
    private static final Dog dd = new Dog();

    //1.私有化构造
    private Dog(){

    }
}

public class TestDog {		
    public static void main(String[] args) {
        //1.获取Dog对象
        for (int i = 0; i < 5; i++) {
            Dog dog = Dog.getInstance();
            System.out.println(dog);
        }
    }
}

输出结果:
com.itheima.demo02_singleInstance.Dog@14ae5a5
com.itheima.demo02_singleInstance.Dog@14ae5a5
com.itheima.demo02_singleInstance.Dog@14ae5a5
com.itheima.demo02_singleInstance.Dog@14ae5a5
com.itheima.demo02_singleInstance.Dog@14ae5a5
5. 懒汉单例设计模式
/**
 * 要求Cat类采用单例模式中的懒汉式
 */
public class Cat {

    //1.私有化构造
    private Cat(){}

    //2.内部定义一个Cat类的对象
    private static Cat cc = null;

    //3.提供静态方法,多线程情况下 需要使用synchronized保证该方法的原子性
    public synchronized static Cat getInstance(){
        //判断
        if (cc == null) {
            //如果不加synchronized,可能会出现
            //线程1执行到这,被线程2抢走了
            //线程2也进来了,执行到这
            cc = new Cat();
        }
        //再返回
        return cc;
    }
}

public class TestCat {
    public static void main(String[] args) {
        //1.获取Cat对象
        for (int i = 0; i < 5; i++) {
            Cat cc = Cat.getInstance();
            System.out.println(cc);
        }
    }
}

输出结果:
com.itheima.demo02_singleInstance.Cat@14ae5a5
com.itheima.demo02_singleInstance.Cat@14ae5a5
com.itheima.demo02_singleInstance.Cat@14ae5a5
com.itheima.demo02_singleInstance.Cat@14ae5a5
com.itheima.demo02_singleInstance.Cat@14ae5a5

第二章 多例设计模式【重点】

1. 多例设计模式的介绍
多例设计模式保证我们的类具有指定个数的对象
2. 多例设计模式的实现步骤
a.私有化构造(不让别人可以正常创建对象)
b.在类内部创建一个private static修饰的集合,用于保存我们自己创建的对象
c.使用静态代码块,向集合中添加指定个数对象
d.通过一个public static静态方法,随机返回集合中的某个对象    

3. 多例设计模式的代码实现
/**
 * 要求Pig类使用多例设计模式
 */
public class Pig {
    //0.定义一个变量,指定集合中对象个数
    private static final int COUNT = 4;

    //1.私有化构造
    private Pig() {
    }

    //2.创建一个集合
    private static ArrayList<Pig> list = new ArrayList<Pig>();

    //3.静态代码块
    static {
        //添加指定个数的对象
        for (int i = 0; i < COUNT; i++) {
            list.add(new Pig());
        }
    }

    //4.提供一个静态方法
    public static Pig getInstance() {
        int index = new Random().nextInt(COUNT);
        Pig pig = list.get(index);
        return pig;
    }
}
public class TestPig {
    public static void main(String[] args) {
        //1.获取Pig对象
        for (int i = 0; i < 10; i++) {
            Pig p1 = Pig.getInstance();
            System.out.println(p1);
        }
    }
}

输出结果:
com.itheima.demo03_multiInstance.Pig@7f31245a1】
com.itheima.demo03_multiInstance.Pig@6d6f6e282】
com.itheima.demo03_multiInstance.Pig@135fbaa43】
com.itheima.demo03_multiInstance.Pig@45ee12a74】
com.itheima.demo03_multiInstance.Pig@135fbaa4	【重复】
com.itheima.demo03_multiInstance.Pig@6d6f6e28	【重复】
com.itheima.demo03_multiInstance.Pig@7f31245a	【重复】
com.itheima.demo03_multiInstance.Pig@7f31245a	【重复】
com.itheima.demo03_multiInstance.Pig@7f31245a	【重复】
com.itheima.demo03_multiInstance.Pig@135fbaa4	【重复】

第三章 动态代理【理解】

3.1 代理模式介绍
  • 什么是代理

    代理就是被代理者,没有能力或者不愿意完成某件事情,找一个可以帮助其完成该事件的对象,该对象称为代理
    
    
  • 生活中的代理

    我们 通过 中介(房东的代理) 找房东租房子
    我们 通过 外卖平台(店家代理) 订饭吃    
    
    

    在这里插入图片描述

  • 代码中的代理案例

    a.用户登录到我们的系统后,我们的系统会为其产生一个ArrayList集合对象,内部存储了一些用户信息
    b.这个对象需要被传给后面的很多其它对象,但要求其它对象不能对这个ArrayList对象执行添加、删除、修改操作,只能get()获取元素
    c.分析: 我们无法控制用户如何操作集合,我们可以给这个集合找一个代理,判断他会判断方法,如果是和增删改有关的直接抛出异常(不让操作),如果是获取相关的找到真正得被代理集合,获取数据即可
    
     
    /**
     * 此类就是普通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;
        }
    }
    
    
3.2 动态代理概述
动态代理和静态代理区别在于代理类是否已经写好,
	上面案例中就是静态代理,代理类ArrayListProxy已经编译时期定义好了
    而动态代理,它的代理类在运行时期通过代码动态生成!!!
     
动态代理的作用:
	拦截对真实对象(被代理对象)方法的直接访问,增强真实对象(被代理对象)方法的功能进行增强(减弱)        

3.3 案例引出

public class DynamicProxy {
    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 = Collections.unmodifiableList(arr);
		//unmodifiableList 该方法返回的就是arr的代理对象,类似于我们自己的ArraylistProxy对象
        //但是unmodifiableList生成的代理对象,是通过动态方式在运行时期创建出来
        //3.调用方法
//        list.add("李四");
//        list.remove(1);
//        list.set(1, "28");
        System.out.println(list.get(2));
    }
}

3.4 重点类和方法

1.java.lang.reflect.Proxy类 他可以为我们动态生成一个对象的代理对象
    public static Object newProxyInstance(
    ClassLoader classLoader, //类加载器,一般我们使用和被代理对象一样类加载器
    Class[] interfaces, // 被代理对象实现的所有接口的字节码文件数组
    InvocationHandler h);//处理类对象,用于拦截我们调用的所有方法,判断到底是否应该被代理对象的真实方法

2.InvocationHandler处理类,实际上它是一个接口
    //invoke方法就是用于拦截我们调用的真实方法
    public Object invoke(Object proxy, Method method, Object[] args)
    					Object proxy  代理对象
    					Method method 被拦截到的方法
    					Object[] args 被拦截到方法的参数,如果没有就是null

3.5 动态代理综合案例

public class DynamicProxy {
    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.调用unmodifiableList
        List<String> list = unmodifiableList(arr);
//        list.add("aaa");
//        list.set(1, "28");
//        list.remove(1);
//        System.out.println(list.get(1));
        System.out.println(list.indexOf("18"));

    }
    //要求该方法和Collections的unmodifiableList一样,接收一个集合,返回一个该集合的代理对象(是动态代理对象)
    public static List<String> unmodifiableList(List<String> arr){
        //1.使用API 创建一个动态代理对象
        List<String> list = (List<String>) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), arr.getClass().getInterfaces(), new InvocationHandler() {
            //该方法就是用来拦截真实对象方法
            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;
    }
}

3.6 动态代理的优缺点总结

Proxy创建动态代理的优点: 
	  a,可以为任意接口的实现类做动态代理
      b.极大提高了我们的开发效率
      c.不会改变被代理对象的代码
Proxy创建动态代理的缺点:  
	  java的Proxy创建动态代理必须有接口,没有接口不行(以后的CGLib可以)       

第四章 Lombok【自学扩展】

第五章 工厂设计模式

1.工厂模式概述
以前我们创建对象,都是通过直接new的方式创建的
而工厂模式,将创建对象的过程交给工厂去执行,我们只从工厂中获取对象即可

2.工厂模式作用
解决类与类之间的耦合问题

3.工厂模式实现步骤
a.提供一个所有类的父类/接口,提供一个Car接口
b.我们的各种实现类都需要实现该接口,重写接口中的方法 
c.提供一个返回不同实现类对象的工厂    

4.工厂模式实现代码
/**
 * 所有汽车的共同接口
 */
public interface Car {
    void run();
}

public class Aotuo implements Car{
    public void run() {
        System.out.println("奥拓以8公里/小时的速度慢游...");
    }
}
public class BenChi implements Car{
    public void run() {
        System.out.println("奔驰以500公里/小时的速度奔驰...");
    }
}
public class FaLaLi implements Car{
    public void run() {
        System.out.println("法拉利以800公里/小时的速度飞驰...");
    }
}
/**
 * 提供工厂
 */
public class CarFactory {
    //定义方法,生产汽车
    public static Car getACar(int id) {
        //返回一辆真正的汽车对象
        if (id == 1) {
            return new Aotuo();
        } else if (id == 2) {
            return new BenChi();
        } else if (id == 3) {
            return new FaLaLi();
        }else{
            throw new NoSuchIdCarException("您的id:"+id+"不存在!");
        }
    }
}

public class TestCar {
    public static void main(String[] args) {
        //1.创建一辆汽车
        Car aCar = CarFactory.getACar(2);
        aCar.run();
    }
}

补充:我们可以使用配置文件,来代替具体的代码中的id值
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();
    }
}    

总结
能够说出单例设计模式的好处【重点】
    可以让一个类只有一个对象
    饿汉式: 直接在类内部定义本类对象并创建对象
    懒汉式: 在类内部定义本类对象,在getInstance方法中判断再创建对象
能够说出多例模式的好处【重点】
    可以让一个类只有指定个数的对象
    在类内部创建一个集合,用来保存多个本类的对象
    一般来说我们都使用静态代码块向集合中添加固定个数的对象    
能够说出动态代理模式的作用【理解】
    在程序运行期间,为一个被代理对象动态创建一个代理对象
    当我们调用 代理对象的方法时,都会被拦截,拦截之后我们可以判断   
能够使用Proxy的方法生成代理对象【理解】
    Proxy.newProxyInstance(ClassLoader cl,Class[] interfaces,InvocationHandler handler)
        
    InvocationHandler接口
        //invoke方法就是用于拦截的
        public Object invoke(Object proxy,Method method,Object[] args);
										  被调用的方法	被调用的方法时的参数
       在此方法中我们会自己判断
               如果满足条件,我们正常调用:   method.invoke(被代理对象,args);                              	  如果不满足条件,我们不让调用: 什么都不做,抛出异常,输出一句话...
        
        
能够使用工厂模式编写java程序【重点】
                   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值