zoukankan      html  css  js  c++  java
  • 设计模式 java

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

    单例(Singleton)设计模式

    所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象系统的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的

    饿汉式实现

    public class SingletonTest1 {
        public static void main(String[] args) {
            // Bank bank1 = new Bank();   私有化后就不能这样调用了
            Bank bank1 = Bank.getInstance();
            Bank bank2 = Bank.getInstance();
    
            System.out.println(bank1 == bank2);
    
        }
    }
    
    class Bank{
        // 1. 私有化类的构造器,私有化后,不能通过Bank bank1 = new Bank();方式在外部创建对象了
        private Bank(){
    
        }
    
        // 2. 内部创建类的对象
        // 4. 要求此对象也必须声明为静态的
        private static Bank instance = new Bank();
    
        // 提供公共的方法,返回类的对象
        public static Bank getInstance(){
            return instance;
        }
    }
    

    懒汉式实现

    线程不安全

    public class SingletonTest2 {
        public static void main(String[] args) {
            Order order1 = Order.getInstance();
            Order order2 = Order.getInstance();
            System.out.println(order1 == order2);
        }
    }
    
    class Order{
        // 1.私有化类的构造器
        private Order(){
    
        }
    
        // 2.声明当前类对象,没有初始化
        // 4.此对象也必须声明为static的
        private static Order instance = null;
    
        // 3. 声明public、static的返回当前类对象的方法
        public static Order getInstance(){
            if(instance == null){
                instance = new Order();
            }
            return instance;
        }
    }
    

    线程安全

    低效率版本

    public class SingletonTest2 {
        public static void main(String[] args) {
            Order order1 = Order.getInstance();
            Order order2 = Order.getInstance();
            System.out.println(order1 == order2);
        }
    }
    
    class Order{
        private Order(){
    
        }
    
        private static Order instance = null;
        public static synchronized Order getInstance(){   //锁是类本身,Order.class
            if(instance == null){
                instance = new Order();
            }
            return instance;
        }
    }
    

    低效率版本的另一种写法

    public class SingletonTest2 {
        public static void main(String[] args) {
            Order order1 = Order.getInstance();
            Order order2 = Order.getInstance();
            System.out.println(order1 == order2);
        }
    }
    
    class Order{
        private Order(){
    
        }
    
        private static Order instance = null;
        public static Order getInstance(){   //锁是类本身,Order.class
            synchronized (Order.class){
                if(instance == null){
                    instance = new Order();
                }
                return instance;
            }
    
        }
    }
    

    升级版

    public class SingletonTest2 {
        public static void main(String[] args) {
            Order order1 = Order.getInstance();
            Order order2 = Order.getInstance();
            System.out.println(order1 == order2);
        }
    }
    
    class Order {
        private Order() {
    
        }
    
        private static Order instance = null;
    
        public static Order getInstance() {   //锁是类本身,Order.class
            if (instance == null) {
                synchronized (Order.class) {
                    if (instance == null) {
                        instance = new Order();
                    }
    
                }
    
            }
            return instance;
        }
    }
    

    区分饿汉式和懒汉式

    饿汉式:

    	坏处:对象加载时间过长(一开始就直接创建了对象)
    	好处:线程安全
    

    懒汉式:

    	好处:延迟对象的创建
    	坏处:线程不安全
    

    单例模式的优点

    由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

    单例设计模式的应用场景

    1. 网站的计数器,一般也是单例模式实现,否则难以同步
    2. 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加
    3. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源
    4. 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。

    模板方法设计模式(TemplateMethod)

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

    解决的问题:

    1. 当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现
    2. 换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式

    类似于python中的装饰器

    例子一,统计code() 函数所花费时间。不同子类重写code() 即可

    package template;
    
    public class TemplateTest {
        public static void main(String[] args) {
            SubTemplate t = new SubTemplate();
            t.spendTime();
    
        }
    }
    
    abstract class Template{
    
        // 计算某段代码执行所需要花费的时间
        public void spendTime(){
            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(){
            for(int i = 2;i <=1000;i++){
                boolean isFlag = true;
                for(int j = 2;j <= Math.sqrt(i);j++){
    
                    if(i % j == 0){
                        isFlag = false;
                        break;
                    }
                }
                if (isFlag){
                    System.out.println(i);
                }
            }
        }
    }
    

    例子2

    // 抽象类的应用:模板方法的设计模式
    public class TemplateMethodTest {
        public static void main(String[] args) {
            BankTemplateMethod btm = new DrawMoney();
            btm.process();
    
            BankTemplateMethod btm2 = new ManageMoney();
            btm2.process();
        }
    }
    
    abstract class BankTemplateMethod {
        // 具体方法
        public void takeNumber() {
            System.out.println("取号排队");
        }
    
        public abstract void transact(); //办理具体的业务 //钩子方法
    
        public void evaluate() {
            System.out.println("反馈评分");
        }
    
        //模板方法,把基本操作组合到一起,子类一般不能重写
        public final void process(){
            this.takeNumber();
    
            this.transact();  //像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码
    
            this.evaluate();
        }
    }
    
    class DrawMoney extends BankTemplateMethod {
        public void transact(){
            System.out.println("我要取款!");
        }
    }
    
    class ManageMoney extends BankTemplateMethod{
        public void transact() {
            System.out.println("我要理财!我这里有2000万美元!");
        }
    }
    

    代理模式(Proxy)

    概述:代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。

    应用场景:

    • 安全代理:屏蔽对真实角色的直接访问
    • 远程代理:通过代理类处理远程方法调用(RMI)
    • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100mb,在打开文件时,不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开

    分类:

    • 静态代理:(静态定义代理类)
    • 动态代理:(动态生成代理类)
      • JDK自带的动态代理,需要反射等知识

    例子1:

    package template;
    
    public class NetWorkTest {
        public static void main(String[] args) {
            Server server = new Server();
            ProxyServer proxyServer = new ProxyServer(server);
            proxyServer.browse();
    
        }
    }
    
    interface NetWork{
        public void browse();
    }
    
    //被代理类
    class Server implements NetWork{
    
        @Override
        public void browse() {
            System.out.println("真实的服务器访问网络");
    
        }
    }
    
    //代理类
    class ProxyServer implements NetWork{
        private NetWork work;
        public ProxyServer(NetWork work){
            this.work = work;
        }
    
        public void check(){
            System.out.println("联网之前的检查工作");
        }
    
        @Override
        public void browse() {
            check();
    
            work.browse();
    
        }
    }
    

    例子2:

    package template;
    
    public class StaticProxyTest {
        public static void main(String[] args) {
            Star s = new Proxy(new RealStar());
            s.confer();
            s.signContract();
            s.bookTicket();
            s.sing();
            s.collectMoney();
        }
    }
    
    interface Star {
        void confer(); // 面谈
    
        void signContract(); //签合同
    
        void bookTicket(); // 订票
    
        void sing(); //唱歌
    
        void collectMoney(); //收钱
    }
    
    //被代理类
    class RealStar implements Star {
        public void confer() {
    
        }
    
        public void signContract() {
    
        }
    
        public void bookTicket() {
    
        }
    
        public void sing() {
            System.out.println("明星:歌唱~~~");
        }
    
        public void collectMoney() {
    
        }
    }
    
    // 代理类
    class Proxy implements Star {
        private Star real;
    
        public Proxy(Star real) {
            this.real = real;
        }
    
        public void confer() {
            System.out.println("经纪人面谈");
        }
    
        public void signContract() {
            System.out.println("经纪人签合同");
        }
        public void bookTicket() {
            System.out.println("经纪人订票");
        }
    
        public void sing() {
            real.sing();
        }
    
        public void collectMoney() {
            System.out.println("经纪人收钱");
        }
    }
    
  • 相关阅读:
    android系列7.单元测试学习
    DELPHI DATASNAP 2010 入门操作(2)不写一行代码,绿色三层我也行
    基于Delphi的融合DLL中的窗口
    Delphi环境中编写调用DLL的方法和技巧 【转】
    利用Cookies实现ASP.NET跨域单点登录
    为项目安装添加WEB调用本地应用程序功能
    利用C#动态编译功能实现像Javascript中的Eval的功能来将一段字符串进行数学运算
    多音节单词的重读音节的位置飘雪搜狐博客
    NDK开发详细讲解转载自c101zxg的博客_赤松子耶_新浪博客
    Computer Vision and Image Processing Journal
  • 原文地址:https://www.cnblogs.com/dongye95/p/15679288.html
Copyright © 2011-2022 走看看