zoukankan      html  css  js  c++  java
  • 设计模式(连载)

    先大话一下设计模式:

    设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索。也就是经典问题的经典解决。

    1:单例模式

    • 1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
    • 2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
    • 3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

    a.饿汉式

    package com.test.designmode;
    
    /**
     * 单例模式(饿汉式)
     * 
     * @author lihuangfeng
     *
     */
    public class SingleInstance {
    
        // 1.私有化构造方法
        private SingleInstance() {
    
        }
    
        // 2.在内部创建实例
        private static SingleInstance instance = new SingleInstance();
    
        // 3.提供方法给外部获得实例,由于类的外部不能创建对象,所以此方法需要设置为static
        public static SingleInstance getInstance() {
            return instance;
        }
    
    }

    b.懒汉式

    package com.test.designmode;
    
    /**
     * 单例模式(懒汉式)
     * 
     * @author lihuangfeng
     *
     */
    public class SingleInstance2 {
    
        // 1.私有化构造方法
        private SingleInstance2() {
    
        }
    
        // 2.在内部创建引用但不赋值,一旦外部调用再创建对象
        private static SingleInstance2 instance;
    
        // 3.提供方法给外部获得实例,由于类的外部不能创建对象,所以此方法需要设置为static
        public synchronized static SingleInstance2 getInstance() {
            if (instance == null) {
                instance = new SingleInstance2();
            }
            return instance;
        }
    
    }

    优化:

    参见https://blog.csdn.net/zhangerqing/article/details/8194653

    2:模版方法模式

    抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

      解决的问题

    • 当功能内部一部分实现(或流程)是确定(一般模板方法模式都会在方法上加final,防止被重写),或者父类只规定流程,而不做任何实现,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
    • 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式
    package com.test.designmode;
    
    /**
     * 模版方法:计算某段不确定的代码执行时间
     * 
     * @author lihuangfeng
     *
     */
    public class TemplateMethod {
    
        public static void main(String[] args) {
            SubTemplate subTemplate = new TemplateMethod().new SubTemplate();
            subTemplate.getTime();
        }
    
        abstract class Template {
    
            public final void getTime() {
                long start = System.currentTimeMillis();
                code();
                long end = System.currentTimeMillis();
                System.out.println("执行时间是:" + (end - start));
            }
    
            public abstract void code();
        }
    
        class SubTemplate extends Template {
    
            @Override
            public void code() {
                int sum = 0;
                for (int i = 0; i <= 100000; i++) {
                    sum += i;
                }
                System.out.println("sum:" + sum);
            }
    
        }
    }

    3:工厂方法模式

    定义一个用于创建对象的接口,让子类决定实例化哪一个类,也就是创建什么工厂对象,就生产什么样的产品。FactoryMethod使一个类的实例化延迟到其子类。

    适用性:

    1. 当一个类不知道它所必须创建的对象的类的时候

    2. 当一个类希望由它的子类来指定它所创建的对象的时候

    3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候

    package com.test.designmode;
    
    /**
     * 工厂方法
     * 
     * @author lihuangfeng
     *
     */
    public class FactoryMethod {
    
        /**
         * 定义一个工厂接口
         * 
         * @author lihuangfeng
         *
         */
        interface Factory {
    
            public Product produce();
        }
    
        class ClothFactory implements Factory {
    
            @Override
            public Cloth produce() {
                System.out.println("工厂正在生产衣服...");
                return new Cloth();
            }
    
        }
    
        class ShoesFactory implements Factory {
    
            @Override
            public Shoes produce() {
                System.out.println("工厂正在生产鞋子...");
                return new Shoes();
            }
    
        }
    
        interface Product {
            public void prodInfo();
        }
    
        class Shoes implements Product {
    
            @Override
            public void prodInfo() {
                System.out.println("鞋子...");
            }
    
        }
    
        class Cloth implements Product {
    
            @Override
            public void prodInfo() {
                System.out.println("衣服...");
            }
    
        }
    
        public static void main(String[] args) {
            Factory shoesFacroty = new FactoryMethod().new ShoesFactory();
            Product product = shoesFacroty.produce();
            product.prodInfo();
    
        }
    }

    4:代理模式

    代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法

    a.静态代理

    package com.test.designmode;
    
    /**
     * 静态代理
     * 
     * @author lihuangfeng
     *
     */
    public class StaticProxy {
    
        public static void main(String[] args) {
            // 买房子的人找到代理商
            HouseProxySeller houseProxySeller = new StaticProxy().new HouseProxySeller();
            houseProxySeller.sellProdcut();
        }
    
        // 定义一个Seller接口,存在一个未实现的sellProduct方法
        interface Seller {
            void sellProdcut();
        }
    
        // 真正的卖房人
        class HouseSeller implements Seller {
    
            @Override
            public void sellProdcut() {
                System.out.println("我要卖房子....");
    
            }
    
        }
    
        // 房产代理
        class HouseProxySeller implements Seller {
            HouseSeller houseSeller;// 房产代理的被代理人
    
            @Override
            public void sellProdcut() {
                houseSeller = new HouseSeller();
                System.out.println("我代替别人卖房子....");
                houseSeller.sellProdcut();
            }
    
        }
    
    }

    b.动态代理

    • 动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象
    • static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  直接创建一个动态代理对象
    package com.test.designmode;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 动态代理
     * 
     * @author lihuangfeng
     *
     */
    public class DynamicProxy {
    
        public static void main(String[] args) {
            PostOffice postOffice = new PostOffice();
            Dothings express = (Dothings) postOffice.bind(new Express());
            express.doing();
    
            Dothings telCharge = (Dothings) postOffice.bind(new TelCharge());
            telCharge.doing();
        }
    
        // 动态代理不限于某一个类,它是针对一个接口来服务,可以代理该接口的所有实现类。这就涉及到反射
        // 邮政不仅代办理快递,也可以代交电话费,代交交水电非等,其实和这类似
        interface Dothings {
            void doing();
        }
    
        static class Express implements Dothings {
    
            @Override
            public void doing() {
                System.out.println("代办快递...");
    
            }
    
        }
    
        static class TelCharge implements Dothings {
    
            @Override
            public void doing() {
                System.out.println("代交话费...");
    
            }
    
        }
    
        static class PostOffice implements InvocationHandler {
    
            Object obj;// 被代理对象
    
            public Object bind(Object o) {
                obj = o;
                return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
            }
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object ret = method.invoke(obj, args);
                return ret;
            }
    
        }
    
    }

    5:生产者,消费者模式

    生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

    这个阻塞队列就是用来给生产者和消费者解耦的。纵观大多数设计模式,都会找一个第三者出来进行解耦,如工厂模式的第三者是工厂类,模板模式的第三者是模板类。在学习一些设计模式的过程中,如果先找到这个模式的第三者,能帮助我们快速熟悉一个设计模式。

    在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

    package com.test.designmode;
    
    /**
     * 
     * 生产者/消费者问题 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,
     * 店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,
     * 如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下, 如果店中有产品了再通知消费者来取走产品。
     * 
     * 分析: 1.生产者和消费者都应该是可实现多线程的,也就是可以有多个生产者,也可以有多个消费者 2.产品的数量由店员把控,店员相当于媒介
     * 3.共享资源为产品,所以在多线程情况下要控制线程安全
     * 
     * @author lihuangfeng
     *
     */
    public class ProduceCustomerMode {
    
        public static void main(String[] args) {
            Clerk clerk = new Clerk();
            Producer p1 = new Producer(clerk);
            Consumer c1 = new Consumer(clerk);
            Thread t1 = new Thread(p1);// 一个生产者的线程
            Thread t3 = new Thread(p1);
            Thread t2 = new Thread(c1);// 一个消费者的线程
    
            t1.setName("生产者1");
            t2.setName("消费者1");
            t3.setName("生产者2");
    
            t1.start();
            t2.start();
            t3.start();
    
        }
    
        /**
         * 生产者生产产品将产品交给店员(Clerk)
         * 
         * @author lihuangfeng
         *
         */
        static class Clerk {// 店员
            int product;
    
            public synchronized void addProduct() {// 生产产品
                if (product >= 20) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } else {
                    product++;
                    System.out.println(Thread.currentThread().getName() + ":生产了第" + product + "个产品");
                    notifyAll();
                }
            }
    
            public synchronized void consumeProduct() {// 消费产品
                if (product <= 0) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } else {
                    System.out.println(Thread.currentThread().getName() + ":消费了第" + product + "个产品");
                    product--;
                    notifyAll();
                }
            }
        }
    
        static class Producer implements Runnable {// 生产者
            Clerk clerk;
    
            public Producer(Clerk clerk) {
                this.clerk = clerk;
            }
    
            public void run() {
                System.out.println("生产者开始生产产品");
                while (true) {
                    try {
                        Thread.currentThread().sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    clerk.addProduct();
    
                }
            }
        }
    
        static class Consumer implements Runnable {// 消费者
            Clerk clerk;
    
            public Consumer(Clerk clerk) {
                this.clerk = clerk;
            }
    
            public void run() {
                System.out.println("消费者消费产品");
                while (true) {
                    try {
                        Thread.currentThread().sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    clerk.consumeProduct();
                }
            }
        }
    
    }
  • 相关阅读:
    leetcode206题实现反转链表(c语言)
    V22017编写C/C++时没有与参数列表匹配的重载函数实例
    3DMAX导出到Unity坐标轴转换问题
    ihandy2019笔记编程真题
    模糊数学中合成算子的计算方法
    点击Button按钮实现页面跳转
    做HTML静态页面时遇到的问题总结
    pip换源
    Python正课146 —— DRF 进阶7 JWT补充、基于权限的角色控制、django缓存
    Python正课145 —— DRF 进阶6 自定制频率、接口文档、JWT
  • 原文地址:https://www.cnblogs.com/pjlhf/p/8658618.html
Copyright © 2011-2022 走看看