zoukankan      html  css  js  c++  java
  • 设计模式读书笔记

    这段时间学习了一下软件开发中的设计模式,这篇读书笔记就谈谈我对设计模式的理解。

    设计模式不是一套api,而是一种可复用的、一般性的解决方式,类似于以前谈过的MSF,其官方定义如下:设计模式(design pattern)是软件开发人员在软件开发过程中面临的一般问题的解决方案。设计模式的提出本身是基于面向对象的语言的,没有了面向对象的继承与多态,所有设计模式都玩不转了。设计模式分为三大类,创建型、结构型、行为型,这次就主要谈谈创建型设计模式。

    首先是最常见的工厂模式,官方的说法是:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。这句话真的很难懂,所以不如举个例子,到汽车厂提车,无论宝马、奥迪还是奥拓只要提就行了,不必管具体的制造细节。这样的说法感觉清晰了些,可以看出工厂模式提供了一定程度上的封装,但具体它要实现怎样的目的呢?放一段Java源码:

    public interface Shape {
       void draw();
    }
    
    public class Rectangle implements Shape {
    
       @Override
       public void draw() {
          System.out.println("Inside Rectangle::draw() method.");
       }
    }
    
    public class Square implements Shape {
    
       @Override
       public void draw() {
          System.out.println("Inside Square::draw() method.");
       }
    }
    
    public class Circle implements Shape {
    
       @Override
       public void draw() {
          System.out.println("Inside Circle::draw() method.");
       }
    }
    
    public class ShapeFactory {
    
       public Shape getShape(String shapeType){
          if(shapeType == null){
             return null;
          }        
          if(shapeType.equalsIgnoreCase("CIRCLE")){
             return new Circle();
          } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
             return new Rectangle();
          } else if(shapeType.equalsIgnoreCase("SQUARE")){
             return new Square();
          }
          return null;
       }
    }

    这样一切都清晰了,用我自己的话说,工厂模式实现的是对一类产品族的封装。其实大家多少都用过工厂模式,当初学习C++虚基类以及Java接口的时候,肯定尝试过通过一个抽象类实现各种相应的实体类,这个过程其实即使工厂模式的核心,即基于接口与实现技术,对于C++也可以说是虚基类与继承技术。要说工厂模式比我们原来写的东西多了什么,就是最后的 ShapeFactory 类以及其 getShape 方法,我相信当初大部分人都不会使用这种写法,但仔细一下这种方式实现了对上层非常干净的封装,对于用户来说再也不需要想着new一个什么样的对象,需要的只是产生一个 ShapeFactory 对象,然后从中 getShape 得到想要的对象,即只要走进汽车工厂就可以取到各种各样的车。

    有句题外话,就是我在看工厂模式的过程中突然模糊了Java中虚基类与接口的区别,查了查才想起来虚基类的部分函数是已经实现了的,子类只需实现那些没有实现的类,而接口的函数全部都是虚函数,实现类必须实现其中全部的函数。

    下面看看单例模式,这种模式要求该类自己负责创建自己,且需确保只有单个对象被创建。为了确保该类不会被实例化,有种骚操作就是把构造函数设为 private ,这样如果该类被 new 则编译器报错,这种操作真的是长见识。具体的单例模式代码还分为懒汉模式和饿汉模式。

    懒汉模式:

    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
        public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
        }  
    } 

    其中 synchronized 关键字是为了保证线程安全,即多线程访问时给对象上锁。从下可以看到饿汉模式不存在这种问题。

    饿汉模式:

    public class Singleton {  
        private static Singleton instance = new Singleton();  
        private Singleton (){}  
        public static Singleton getInstance() {  
        return instance;  
        }  

    这两者的区别就在于,懒汉模式的初始化在被调用时进行,而饿汉模式的初始化在类加载时就进行了,这带来的结果就是懒汉模式更节省内存,但是其本身存在线程不安全的问题,必须使用 sychronized 关键字,所以性能会比较低,一般在单例用的次数少且消耗资源大时使用。

    单例模式这样就讲清楚了,但是带来的新的问题是类到底何时被初始化?我查了相关资料发现,JVM并没有规定类何时被加载(加载到JVM方法区和堆区),但严格规定了何时被初始化,其中最常见的两种情况就是 new 一个类或者调用其静态方法(还包括读取、设置静态字段等情况),一旦出现上述情况类就必须被初始化,而饿汉模式中的static成员instance在类加载时被赋值,同时 new 了自身,所以该类在加载时就初始化,懒汉模式就可以等到被调用再初始化。

    可见,这么短短两段代码中蕴藏着那么多知识,充分体现了第一次提出规范单例模式的程序员的智慧。

    最后再谈谈原型模式。原型模式的目的是创建重复的对象,比如说,如果类的初始化需要很多资源,不如只保存一份相应的对象。从这个角度看,原型模式很像是单例模式的扩展,可以看成是一个产品族的单例集合。看看如下java代码:

    public abstract class Shape implements Cloneable {
       
       private String id;
       protected String type;
       
       abstract void draw();
       
       public String getType(){
          return type;
       }
       
       public String getId() {
          return id;
       }
       
       public void setId(String id) {
          this.id = id;
       }
       
       public Object clone() {
          Object clone = null;
          try {
             clone = super.clone();
          } catch (CloneNotSupportedException e) {
             e.printStackTrace();
          }
          return clone;
       }
    }
    
    public class ShapeCache {
        
       private static Hashtable<String, Shape> shapeMap 
          = new Hashtable<String, Shape>();
    
       public static Shape getShape(String shapeId) {
          Shape cachedShape = shapeMap.get(shapeId);
          return (Shape) cachedShape.clone();
       }
    
       public static void loadCache() {
          Circle circle = new Circle();
          circle.setId("1");
          shapeMap.put(circle.getId(),circle);
    
          Square square = new Square();
          square.setId("2");
          shapeMap.put(square.getId(),square);
    
          Rectangle rectangle = new Rectangle();
          rectangle.setId("3");
          shapeMap.put(rectangle.getId(),rectangle);
       }
    }

    java中自带的 Cloneable 类可以很好地实现原型模式的目的。虽然上述代码有些工厂模式的感觉,但其实原型模式的目的与工厂模式完全不同。但是,原型模式最大的用处之一就是和工厂模式结合,如果把上述代码中的形状改为工厂,具体的形状改为不同的工厂,那么最后的 Cache 提供的就是不同工厂的克隆,这很好地实现了工厂的单例性。

    本文描述了工厂模式、单例模式、原型模式三种常见的创建型设计模式,下次再来说说结构型设计模式。

  • 相关阅读:
    android listview 添加数据
    Android 打开其他程序
    Android 自定义ListView Item侧滑删除
    Intent 传递对象
    openfire Android学习(六)----总结
    openfire Android学习(五)------连接断开重连
    openfire Android 学习(四)----单人聊天和多人聊天(发送消息、接收消息)
    openfire Android学习(三)----会议室创建、加入以及查询会议室中所有成员等
    openfire Android学习(二)----对分组、好友和头像等一些操作
    openfire Android学习(一)----实现用户注册、登录、修改密码和注销等
  • 原文地址:https://www.cnblogs.com/tilmto-Jerry/p/8853456.html
Copyright © 2011-2022 走看看