设计模式的好处以及单例模式、原型模式详解

设计模式(design pattem):是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。从建筑设计引入到计算机科学。

使用设计模式的好处:

高内聚,低耦合

  1. 代码重用性:相同功能,不用多次编写

  2. 可读性:编程规范,便于他人阅读和理解

  3. 可扩展性(可维护性):新增需求功能时,非常方便

  4. 可靠性:新增功能后,不影响原来的功能

设计模式分三种类型(23种):

创建型模式:单例模式、原型模式、工厂模式、抽象工厂模式、建造者模式

结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式

行为型模式:模板方法模式、命令模式、访问者模式、观察者模式、迭代器模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责模式(责任链模式)

设计模式的七大原则:

单一职责:一个类只负责一项职责,各司其职

接口隔离:最小接口原则,不去实现不用的接口方法,对接口进行拆分

依赖倒置:面对接口编程。抽象不应该依赖细节,细节应该起来抽象

里氏替换:使用继承时,子类尽量不要重写父类的方法,可通过聚合、组合、依赖来解决问题

开闭原则 ocp:扩展开放(提供方),对修改关闭(使用方)

迪米特法则:降低类间耦合度

合成复用:尽量使用合成/聚合的方式,而不是使用

设计模式在软件中哪里使用:

面向对象(OO) -> 功能模式 [设计模式+算法(数据结构)] -> 框架 [多种设计模式 ] -> 架构 [服务器集群]

面试官一般会问:项目中使用过哪些设计模式,是如何使用的,解决了哪些问题

单例模式(8中实现方式):

  1. 饿汉式(静态常量)

    class Singleton {
       // 1.构造器私有化(防止new)
       private Singleton() {}
       // 2.类的内部创建对象
       private final static Singleton singleton = new Singleton();
       // 3.向外暴露一个静态的公共方法 getInstance
       public static Singleton getInstance(){
           return singleton;
      }
    }
  2. 饿汉式(静态代码块量)

    class Singleton {
       // 1.构造器私有化(防止new)
       private Singleton() {}
       // 2.类的内部创建对象
       private static Singleton singleton;
       static { // 通过静态代码块创建单例对象
           singleton = new Singleton();
      }
       // 3.向外暴露一个静态的公共方法 getInstance
       public static Singleton getInstance(){
           return singleton;
      }
    }
    // -----------------
    Singleton instance1 = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();
    System.out.println(instance1 == instance2); // true,同一实例
    // -----------------
    /** 饿汉式优缺点
    优点:写法简单,类加载的时候就完成实例化,避免了线程同步的问题
    缺点:类加载的时候就完成实例化,没有达到懒加载的效果。如果从始到终都没用过此实例,会造成内存浪费
    */
  3. 懒汉式(线程不安全), 在开发中不使用该方式!!!

    class Singleton {
       private Singleton() {}
       private static Singleton singleton;
       // 3.只有在条用该方法时,才会去创建实例化对象 (而饿汉式是在类加载时就完成实例化)
       public static Singleton getInstance(){
           if (singleton == null) {
               singleton  = new Singleton();
          }
           return singleton;
      }
    }
    /** 该方式优缺点
    优点:起到懒加载的效果,但只能在单线程下使用
    缺点:如果在多线程下,一个线程进入if (singleton == null),还未来得及创建,另一线程也通过判断条件,这是便会产生多个实例。在开发中不使用该方式!!!
    */
  4. 懒汉式(线程安全,同步方法), 实际开发中不推荐使用。

    class Singleton {
       private Singleton() {}
       private static Singleton singleton;
       // 3.只有在条用该方法时,才会去创建实例化对象 (使用synchronized安全锁,保证线程安全问题)
       public static synchronized Singleton getInstance(){
           if (singleton == null) {
               singleton  = new Singleton();
          }
           return singleton;
      }
    }
    /** 该方式优缺点
    优点:起到懒加载的效果,也解决了线程安全问题
    缺点:效率低。其实实例化对象只需要第一次做,之后直接返回对象即可。实际开发中不推荐使用。
    */
  5. 懒汉式(同步代码块), 在开发中不使用该方式,是无实际意义的!!!

    class Singleton {
       private Singleton() {}
       private static Singleton singleton;
       // 3.只有在条用该方法时,才会去创建实例化对象
       public static Singleton getInstance(){
           if (singleton == null) {
               synchronized (Singleton.class) { //使用synchronized同步代码块,保证线程安全问题
                   singleton  = new Singleton();
              }
          }
           return singleton;
      }
    }
    // 这种写法是想解决上面方式效率低的问题,但却连线程安全都没达到
  6. 双重检查(线程安全,懒加载,效率高), 推荐使用

    class Singleton {
       private Singleton() {}
       // 添加 volatile 关键字:singleton一旦有变化,就会刷新到主内存中,让其他使用的线程可以知道,同时在一定程度上可以达到同步效果
       private static volatile Singleton singleton;
       // 3.双重检查
       public static Singleton getInstance(){
           if (singleton == null) { // 第一次判断是否null
               synchronized (Singleton.class) { // 使用synchronized同步代码块,保证线程安全问题
                   if (singleton == null) { // 第二次判断是否null
                       singleton = new Singleton();
                  }
              }
          }
           return singleton;
      }
    }
    //Double-check概念在多线程中经常使用的
  7. 静态内部类(线程安全,懒加载,效率高), 推荐使用

    // 静态内部类的特点:1 当外部类加载时,静态内部类是不会被加载的;2 当调用静态类方法时,静态内部类才会被加载,而且只会加载一次,是线程安全的
    // 也就是说,静态内部类,既可以达到懒加载的效果,也可以保证线程安全
    class Singleton {
       private Singleton() {}
       // 添加 volatile 关键字:singleton一旦有变化,就会刷新到主内存中,让其他使用的线程可以知道,同时在一定程度上可以达到同步效果
       private static volatile Singleton singleton;
       // 通过静态内部类来实例化
       private static class SingletonInstance {
           private static final Singleton INSTANCE = new Singleton();
      }
       public static Singleton getInstance(){
           return SingletonInstance.INSTANCE;
      }
    }
  8. 枚举,推荐使用

    enum Singleton{
       INSTANCE;
       public void method(){
           System.out.println("hello");
      }
    }
    // -----------------
    Singleton instance1 = Singleton.INSTANCE;
    Singleton instance2 = Singleton.INSTANCE;
    System.out.println(instance1 == instance2); // true
    // -----------------
    // 借助JDK1.5添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建对象

使用单例模式的原因 和 注意细节:

  1. 单例模式保证了 系统内存中,一个类只存一个对象,节省系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提供系统性能

  2. 当想实例化一个单例对象时,必须使用相对的获取对象的方法,而不是new

原型模式 Prototype:

  1. 用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象

  2. 原型模式是一种创建型设计模式,允许一个对象在创建另一个可定制的对象,无需知道创建的细节

  3. 工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝他们自己来实现创建,即 对象.clone()

  4. 浅拷贝(默认)

    对于基本数据类型,直接进行值的拷贝

    对于引用类型,只是引用传递,指向同一个实例。

    public class Sheep implements Cloneable {
    private String name;
    private String color;
    public Sheep(String name, String color) {
    this.name = name;
    this.color = color;
    }
    @Override
    protected Sheep clone() throws CloneNotSupportedException {
    return (Sheep)super.clone();
    }
    }
    // 普通写法 ---------------
    Sheep sheep1 = new Sheep();
    Sheep sheep2 = new Sheep();
    // 原型模式 ---------------
    Sheep sheep3 = sheep1.clone();
    System.out.println(sheep1 == sheep3); // false
  5. 深拷贝

    对于基本数据类型,直接进行值的拷贝

    对于引用类型,会申请存储空间,进行整个对象的拷贝,而不是仅拷贝引用地址。

    深拷贝实现方式1:重写clone方法

    public class Sheep implements Cloneable, Serializable {
    private String name;
    private String color;
    private Sheep friend;
    public Sheep(String name, String color) {
    this.name = name;
    this.color = color;
    }
    @Override
    protected Sheep clone() throws CloneNotSupportedException {
    // 先对基本类型和String进行克隆
    Sheep sheep = (Sheep)super.clone();
    // 在对引用类型进行单独处理
    sheep.friend = (Sheep)friend.clone();
    return sheep;
    }
    }

     

    深拷贝实现方式2:对象序列化(推荐使用)

    public Object SerClone(){
           ByteArrayOutputStream bos = null;
           ObjectOutputStream oos = null;
           ByteArrayInputStream bis = null;
           ObjectInputStream ois = null;
           try {
               // 序列化
               bos = new ByteArrayOutputStream();
               oos = new ObjectOutputStream(bos);
               oos.writeObject(this);
               // 反序列化
               bis = new ByteArrayInputStream(bos.toByteArray());
               ois = new ObjectInputStream(bis);
               Sheep sheep = (Sheep)ois.readObject();
               return sheep;
          } catch (Exception e) {
               e.printStackTrace();
               return null;
          } finally {
               try {
                   bos.close();oos.close();bis.close();ois.close();
              } catch (Exception e) {
                   System.out.println(e.getMessage());
              }
          }
      };

在spring中,bean的创建,就使用了原型模式

// bean.xml
<bean id="user" class="com.auv.bean.User" scope="prototype">
// java
ClassPathXmlApplicationContext("bean.xml");
Object bean = applicationContext.getBean("user")
   
@Override
public Object getBean(String name) {
   return doGetBean(name,null,null,false);
}
// else if (mdb.isPrototype)

 

posted @ 2022-03-13 17:55  迷路小孩  阅读(440)  评论(0)    收藏  举报