1、工厂模式

Factory Pattern 是Java中最常用的设计模式之一。它提供了一种创建对象的最佳方式。
在这种模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

1.1 介绍

  • 意图:定义一个创建对象的接口,让其子类自己决定实例哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

  • 主要解决:主要解决接口选择的问题。

  • 何时使用:我们明确地计划不同条件下创建不同实例。

  • 如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

  • 关键代码:创建过程在其子类执行。

  • 应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

  • 优点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

  • 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是好事。

  • 使用场景:

    • 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
    • 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
    • 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
  • 注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

1.2 实现

实例来源open in new window,我们将创建一个Shape接口和实现Shape接口的实体类。下一步是定义工厂类ShapeFactory。
FactoryPatternDemo,我们的演示类使用ShapeFactory来获取Shape对象。它将ShapeFactory传递信息(CIRCLE / RECTANGLE / SQUARE),以便于获取它所需对象的类型。

图一

1.3 步骤一

创建一个接口 (Shape.java)

pub;ic interface Shape{
   void draw();
}

1.4 步骤二

创建实现接口的实体类 (Rectangle.java)

public class Rectangle implements Shape{
   @Override
   public void draw(){
      System.out.println("Inside Rectangle::draw() mrthod.");
   }
}

Square.java

public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

Circle.java

public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

1.5 步骤三

创建一个工厂,生成基于给定信息的实体类的对象。(ShapeFactory.java)

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;
   }
}

1.6 步骤四

使用该工厂,通过传递类型信息来获取实体类的对象 (FactoryPatternDemo.java)

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();
   }
}

1.7 步骤五

执行程序,输出结果:

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

2、抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是以一个超级工厂为中心创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一个创建对象的最佳方式。

  • 意 图: 提供一个创建一系列相关依赖对象的接口,而无需指定它们具体的类。
  • 主要结局: 接口选择的问题。
  • 何时使用: 系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
  • 如何解决: 在产品族里定义多个产品。
  • 关键代码: 在一个工厂里聚合多个同类产品。
  • 优 点: 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只能使用同一个产品族中的对象。
  • 缺 点: 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的Creator里加代码,又要在具体的里面加代码。
  • 注意事项: 产品族难扩展,产品等级易于扩展。

2.1 实现

  • 1、创建Shape和Color接口和实现这些接口的实体类。
  • 2、创建抽象工厂类AbstractFactory。
  • 3、定义工厂类ShapeFactory和ColorFactory,这两个工厂类都是扩展了AbstractFactory。
  • 4、创建工厂创造器/生成器类FactoryProducter。
  • 5、AbstractFactoryPatternDemo,演示类使用FactoryProducter来获取AbstractFactory对象。它将传递形状信息Shape(CIRCLE / RECTANGLE / SQUARE),以便于获取它所需对象的类型。同时它还向AbstractFactory传递颜色信息Color(RED / GREEN / BLUE),以便于获取它所需对象的类型。

图一

2.2 步骤一

为形状创建一个接口

// Shape.java
public interface Shape{
   void draw();
}

2.3 步骤二

创建实现接口的实体类

// Rectangle.java
public class Rectangle implements Shape{
   @Override
   public  void draw(){
      System.out.print("Inside Rectangle::draw() method.");
   }
}

//Square.java
public class Square implements Shape{
   @Override
   public void draw(){
      System.out.println("Inside Square::draw() method.");
   }
}

//Circle.java
public class Circle implement{
   @Override
   public void draw(){
      system.out.println("Inside Circle::draw() method.");
   }
}

2.4 步骤三

为颜色创建一个接口

//Color.java
public interface Color{
   void fill();
}

2.5 步骤四

创建实现接口的实体类

//Red.java
public class Red implements Color{
   @Override
   public void fill(){
      System.out.println("Inside Red::fill() method.");
   }
} 

//Green.java
public class Green implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Green::fill() method.");
   }
}

//Blue.java
public class Blue implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Blue::fill() method.");
   }
}

2.6 步骤五

为Color和Shape对象创建抽象类来获取工厂

//AbstractFactory.java
public abstract class AbstractFactory{
   public abstract Color getColor(String color);
   public abstract Shape getShape(String shape);
}

2.7 步骤六

创建扩展了AbstractFactory的工厂类,基于给定的信息生成实体类的对象。

//ShapeFactory.java
public class ShapeFactory extends AbstractFactory {
   @Override
   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;
   }

   @Override
   public Color getColor(String color){
      return null;
   }
}
//ColorFactroy.java
public class ColorFactory extends AbstractFactory{
   @Override
   public Shape getShape(String shapeType){
      return null;
   }

   @Override
   public Color getColor(String color){
      if(color == null){
         return null;
      }        
      if(color.equalsIgnoreCase("RED")){
         return new Red();
      } else if(color.equalsIgnoreCase("GREEN")){
         return new Green();
      } else if(color.equalsIgnoreCase("BLUE")){
         return new Blue();
      }
      return null;
   }
}

2.8 步骤七

创建一个工厂创造器/生成器,通过传递形状或颜色信息来获取工厂。

//FactoryProducter.java
public class FactoryProducter{
   public static AbstractFactory getFactory(String choice){
      if(choice.equalsIgnoreCase("SHAPE")){
         return new ShapeFactory();
      }else if(choice.equalsIgnoreCase("COLOR")){
         return new ColorFactory();
      }
      return null;
   }
}

2.9 步骤八

使用FactoryProducter来获取AbstractFactory。通过传递类型信息来获取实体类的对象。

//AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo{
   public static void main(String[] args){
      
      //获取形状工厂
      AbstractFactory shapeType = FactoryProuducter.getFactory("SHAPE");

      //获取形状为 Circle 的对象
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //调用 Circle 的 draw 方法
      shape1.draw();
 
      //获取形状为 Rectangle 的对象
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //调用 Rectangle 的 draw 方法
      shape2.draw();
      
      //获取形状为 Square 的对象
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //调用 Square 的 draw 方法
      shape3.draw();
 
      //获取颜色工厂
      AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
 
      //获取颜色为 Red 的对象
      Color color1 = colorFactory.getColor("RED");
 
      //调用 Red 的 fill 方法
      color1.fill();
 
      //获取颜色为 Green 的对象
      Color color2 = colorFactory.getColor("Green");
 
      //调用 Green 的 fill 方法
      color2.fill();
 
      //获取颜色为 Blue 的对象
      Color color3 = colorFactory.getColor("BLUE");
 
      //调用 Blue 的 fill 方法
      color3.fill();
   }
}

2.10 步骤九

程序输出:

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.

More Read at runoob.comopen in new window

3、单例模式

  • Singleton Pattern是Java中最简单的设计模式之一,属于创建型模式。
  • 这种模式设计到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
  • 注意:
    • 单例类只能有一个实例。
    • 单例类必须自己创建自己的唯一实例。
    • 单例类必须给所有其他对象提供这一实例。

3.1 简要介绍

  • 意 图: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  • 主要解决: 一个全局使用的类频繁地创建与销毁。
  • 何时使用: 当你想控制实例数目,节省系统资源得时候。
  • 如何解决: 判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
  • 关键代码: 构造函数是私有的。
  • 优 点:
    • 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
    • 2、避免对资源的多重占用(比如写文件操作)
  • 缺 点: 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

3.2 实现

  • 1、创建一个SingleObject类。SingleObject类有它的私有构造函数和本身的一个静态实例。
  • 2、SingleObject类提供一个静态方法,供外界获取它的静态实例。
  • 3、SingltPatternDemo,演示类使用SingleObject类来获取SingleObject对象。

图二

3.3 步骤一

创建一个Singleton类

//SingleObject.java
public class SingleObject {
 
   //创建 SingleObject 的一个对象
   private static SingleObject instance = new SingleObject();
 
   //让构造函数为 private,这样该类就不会被实例化
   private SingleObject(){}
 
   //获取唯一可用的对象
   public static SingleObject getInstance(){
      return instance;
   }
 
   public void showMessage(){
      System.out.println("Hello World!");
   }
}

3.4步骤二

从singleton类获取唯一的对象

public class SingletonPatternDemo {
   public static void main(String[] args) {
 
      //不合法的构造函数
      //编译时错误:构造函数 SingleObject() 是不可见的
      //SingleObject object = new SingleObject();
 
      //获取唯一可用的对象
      SingleObject object = SingleObject.getInstance();
 
      //显示消息
      object.showMessage();
   }
}

//output
Hello World!

3.5 单例模式的几种实现方式之懒汉式,线程不安全

  • 是否Lazy初始化:是
  • 是否多线程安全:否
  • 实现难度:易
  • 这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。

这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

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

3.6 懒汉式,线程安全

  • 是否 Lazy 初始化:是
  • 是否多线程安全:是
  • 实现难度:易
  • 描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
  • 优点:第一次调用才初始化,避免内存浪费。
  • 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
  • getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

3.7 饿汉式

  • 是否 Lazy 初始化:是
  • 是否多线程安全:是
  • 实现难度:易
  • 描述:比较常用,但容易产生垃圾对象。
  • 优点:没有加锁,执行效率提高。
  • 缺点:类加载时就初始化,浪费内存。
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

3.8 其他方式

  • 枚举,更简洁,自动支持序列机制,绝对防止多次实例化。
public enum SIngleton{
   INSTANCE;
   public void whateverMethod(){};
}
  • 登记式/静态内部类
public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}
  • 双检锁/双重校验锁(DCL,double-checked locking)
public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

4、建造者模式

5、原型模式

未完待续...【感谢RUNOOBopen in new window