1、单例模式:html
优势:java
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。数据库
使用场景:编程
注意事项:getInstance() 方法中须要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入形成 instance 被屡次实例化。设计模式
1.饿汉式(线程安全,调用效率高,可是,不能延时加载)缓存
// 饿汉式单例 public class Singleton1 { // 指向本身实例的私有静态引用,主动建立 private static Singleton1 singleton1 = new Singleton1(); // 私有的构造方法 private Singleton1(){} // 以本身实例为返回值的静态的公有方法,静态工厂方法 public static Singleton1 getSingleton1(){ return singleton1; } }
咱们知道,类加载的方式是按需加载,且加载一次。。所以,在上述单例类被加载时,就会实例化一个对象并交给本身的引用,供系统使用;并且,因为这个类在整个生命周期中只会被加载一次,所以只会建立一个实例,即可以充分保证单例。安全
优势:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。多线程
缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。若是从始至终从未使用过这个实例,则会形成内存的浪费。并发
2.懒汉式(线程安全,调用效率低,可是,能够延时加载)框架
// 懒汉式单例 public class Singleton2 { // 指向本身实例的私有静态引用 private static Singleton2 singleton2; // 私有的构造方法 private Singleton2(){} // 以本身实例为返回值的静态的公有方法,静态工厂方法 public static Singleton2 getSingleton2(){ // 被动建立,在真正须要使用时才去建立 if (singleton2 == null) { singleton2 = new Singleton2(); } return singleton2; } }
咱们从懒汉式单例能够看到,单例实例被延迟加载,即只有在真正使用的时候才会实例化一个对象并交给本身的引用。
这种写法起到了Lazy Loading的效果,可是只能在单线程下使用。若是在多线程下,一个线程进入了if (singleton == null)判断语句块,还将来得及往下执行,另外一个线程也经过了这个判断语句,这时便会产生多个实例。因此在多线程环境下不可以使用这种方式。
3.双重检测锁式(因为JVM底层内部模型缘由,偶尔会出现问题。不建议使用)
public class Singleton { private static Singleton instance; //程序运行时建立一个静态只读的进程辅助对象 private static readonly object syncRoot = new object(); private Singleton() { } public static Singleton GetInstance() { //先判断是否存在,不存在再加锁处理 if (instance == null) { //在同一个时刻加了锁的那部分程序只有一个线程能够进入 lock (syncRoot) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
Double-Check概念对于多线程开发者来讲不会陌生,如代码中所示,咱们进行了两次if (singleton == null)检查,这样就能够保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。
使用双重检测同步延迟加载去建立单例的作法是一个很是优秀的作法,其不但保证了单例,并且切实提升了程序运行效率
优势:线程安全;延迟加载;效率较高。
4.静态内部类式(线程安全,调用效率高,能够延时加载)
public sealed class Singleton{ private static class SingletonInstance{ //在第一次引用类的任何成员时建立实例,公共语言运行库负责处理变量初始化 private static final Singleton instance=new Singleton(); } private Singleton() { } public static Singleton getInstance(){ return SingletonInstance.instance; } }
外部类没有static属性,则不会像饿汉式那样当即加载对象。
只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的。instance是static final类型,保证了内存中只有这样一个实例存在,并且只能被赋值一次,从而保证了线程安全性。
兼备了并发高效调用和延迟加载的优点!
5.枚举实现单例模式
public enum Singleton{ //定义一个枚举元素,它就表明了Singleton的一个实例 INSTANCE; //单例能够有本身的操做 public void singletonOperation(){ //功能处理(可额外添加须要的操做) } }
优势:实现简单
枚举自己就是单例模式。因为JVM根本上提供保障,避免经过反射和反序列化的漏洞
缺点:无延迟加载
2、工厂模式
实现了建立者和调用者的分离。
分类:简单工厂模式、工厂方法模式、抽象工厂模式
面向对象设计的基本原则
OCP(开闭原则):一个软件的实体应当对扩展开放,对修改关闭。
DIP(依赖倒转原则):要针对接口编程,不要针对实现编程。
LOD(迪米特法则):只与你直接的朋友通讯,而避免和陌生人通讯。
工厂核心本质:
实例化对象,用工厂方法代替new操做,将选择实现类、建立对象统一管理和控制,从而将调用者跟咱们的实现类解耦。
简单工厂模式
咱们将建立一个 Shape 接口
public interface Shape { void draw(); }
实现 Shape 接口的实体类
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 { //使用 getShape 方法获取形状类型的对象 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; } }
使用该工厂,经过传递类型信息来获取实体类的对象。
public class FactoryPatternDemo { public static void main(String[] args) { ShapeFactory shapeFactory = new ShapeFactory(); //获取 Circle 的对象,并调用它的 draw 方法 Shape shape1 = shapeFactory.getShape("CIRCLE"); //调用 Circle 的 draw 方法 shape1.draw(); //获取 Rectangle 的对象,并调用它的 draw 方法 Shape shape2 = shapeFactory.getShape("RECTANGLE"); //调用 Rectangle 的 draw 方法 shape2.draw(); //获取 Square 的对象,并调用它的 draw 方法 Shape shape3 = shapeFactory.getShape("SQUARE"); //调用 Square 的 draw 方法 shape3.draw(); } }
执行程序,输出结果:
Inside Circle::draw() method. Inside Rectangle::draw() method. Inside Square::draw() method.
2、工厂方法模式
public interface IFactory { ICar CreateCar(); }
建立抽象产品
public interface ICar { void GetCar(); }
建立具体工厂代码:
// 具体工厂类: 用于建立跑车类 public class SportFactory : IFactory { public ICar CreateCar() { return new SportCar(); } } // 具体工厂类: 用于建立越野车类 public class JeepFactory : IFactory { public ICar CreateCar() { return new JeepCar(); } } // 具体工厂类: 用于建立两厢车类 public class HatchbackFactory : IFactory { public ICar CreateCar() { return new HatchbackCar(); } }
建立具体产品代码:
// 具体产品类: 跑车 public class SportCar : ICar { public void GetCar() { System.out.println("跑车"); } } // 具体产品类: 越野车 public class JeepCar : ICar { public void GetCar() { System.out.println("越野车"); } } // 具体产品类: 两箱车 public class HatchbackCar : ICar { public void GetCar() { System.out.println("两箱车"); } }
建立客户端代码:
class Client{ public static void main(string[] args){ ICar c1 = new SportFactory.CreateCar();
ICar c2 = new JeepFactory .CreateCar();
ICar c3 = new HatchbackFactory .CreateCar();
c1.GetCar();
c2.GetCar();
c3.GetCar(); } }
工厂方法的优势/缺点:
代理模式: