设计模式篇 —《创建型设计模式》

本文详细介绍了创建型设计模式,包括单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。单例模式确保类只有一个实例;工厂模式用于创建对象,避免暴露创建逻辑;抽象工厂模式提供创建相关对象的接口;建造者模式构建复杂的对象;原型模式通过复制已有对象创建新对象。


创建型模式抽象了实例化过程,他们帮助一个系统独立于如何创建、组合和表示它的那些对象。

  • 一个类创建型模式使用继承改变被实例化的类。

  • 一个对象创建型模式将实例化委托给另一个对象。

1、单例模式

简介:

  • 单例模式:

    • 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。
    • 单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象
  • 意图:

    保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  • 主要解决:

    • 一个全局使用的类频繁地创建与销毁
    • 当您想控制实例数目,节省系统资源的时候

适用场景:

  • Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行
  • 一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件
  • WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来
  • 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等

结构:

image-20210411130604815

  1. 创建一个 SingleObject 类,SingleObject 类有它的私有构造函数和本身的一个静态实例 SingleObject 类提供了一个静态方法,供外界获取它的静态实例
  2. SingletonPatternDemo 使用 SingleObject 类来获取 SingleObject 对象

代码实现:

最好理解的一种模式,分为懒汉式和饿汉式

	/**
     * 饿汉式
     */
    public static class hungrySingleton {
        // 直接创建对象
        public static hungrySingleton instance = new hungrySingleton();
        // 私有化构造函数
        private hungrySingleton() {}

        // 提供对外方法
        public static  hungrySingleton getInstance() {
            return instance;
        }
    }

    /**
     * 懒汉式
     */
    public static class LazySingleton {
        // 声明变量
        private static volatile LazySingleton singleton= null;
        // 私有构造函数
        private LazySingleton() {}
        // 提供对外方法
        public static synchronized LazySingleton getInstance() {
            if (singleton == null) {
              	singleton = new LazySingleton();
            }
            return singleton;
        }
    }

2、工厂方法模式

简介:

  • 举例:

    • 追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基就是生产鸡翅的Factory
  • 工厂模式:

    • 客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。
    • 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行
  • 主要解决:

    • 主要解决接口选择的问题
  • 何时使用:

    • 我们明确地计划不同条件下创建不同实例时
  • 如何解决:

    • 让其子类实现工厂接口,返回的也是一个抽象的产品

适用场景:

  • 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方
  • 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时
  • 设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口

结构:

20210411131739123

  1. 创建一个 Shape 接口和实现 Shape 接口的实体类

  2. 下一步是定义工厂类 ShapeFactory

  3. FactoryPatternDemo 使用 ShapeFactory 来获取 Shape 对象

    它将向 ShapeFactory 传递信息( CIRCLE / RECTANGLE / SQUARE ),以便获取它所需对象的类型

代码实现:

1、创建一个接口

public interface Shape {
   void draw();
}

2、创建实现接口的实体类

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.");
   }
}

3、创建一个工厂,生成基于给定信息的实体类的对象

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

4、使用该工厂,通过传递类型信息来获取实体类的对象

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

3、抽象工厂模式

简介:

  • 举例:

    • 请MM去麦当劳吃汉堡,不同的MM有不同的口味,要每个都记住是一件烦人的事情,我一般采用Factory Method模式,带着MM到服务员那儿,说“要一个汉堡”,具体要什么样的汉堡呢,让MM直接跟服务员说就行了。
  • 工厂方法模式:

    • 核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
    • 是实例工厂的父入口。
  • 目的:

    • 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

结构:

image-20210411122349290

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

适用场景:

  1. 系统换皮肤,换主题。
  2. 生成不通操作系统的程序,如不同账号登录不同的系统。

代码实现:

1、为形状创建接口 并创建实现接口的实体类

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.");
   }
}

2、为颜色创建接口 并创建实现接口的实体类

public interface Color {
   void fill();
}

public class Red implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Red::fill() method.");
   }
}

public class Green implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Green::fill() method.");
   }
}

public class Blue implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Blue::fill() method.");
   }
}

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

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

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

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
   Color getColor(String color) {
      return null;
   }
}

public class ColorFactory extends AbstractFactory {

   @Override
   public Shape getShape(String shapeType){
      return null;
   }

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

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

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

6、使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象

public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {

      //获取形状工厂
      AbstractFactory shapeFactory = FactoryProducer.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();
   }
}

4、建造者模式

简介:

  • 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象
  • 一个 Builder 类会一步一步构造最终的对象,该 Builder 类是独立于其他对象的
  • 举例:
    • MM最爱听的就是“我爱你”这句话了,见到不同地方的MM,要能够用她们的方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到MM我只要按对应的键,它就能够用相应的语言说出“我爱你”这句话了,国外的MM也可以轻松搞掂,这就是我的“我爱你”builder。
  • 建造模式:
    • 将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。
    • 建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。
    • 建造模式可以强制实行一种分步骤进行的建造过程。
  • 主要解决:
    • 主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;
    • 由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定
  • 何时使用:
    • 一些基本部件不会变,而其组合经常变化的时候
  • 如何解决:
    • 将变与不变分离开

适用场景:

  • 去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"
  • JAVA 中的 StringBuilder
  • 需要生成的对象具有复杂的内部结构
  • 需要生成的对象内部属性本身相互依赖

结构:

image-20210411133058069

我们以一家快餐店为例:

一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)

汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中 冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中

创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类, 以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中

然后创建一个 Meal 类,带有 ItemArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder

最后使用 MealBuilder 来创建一个 Meal

代码实现:

1、创建一个表示食物条目和食物包装的接口

public interface Item {
   public String name();
   public Packing packing();
   public float price();    
}

public interface Packing {
   public String pack();
}

2、创建实现 Packing 接口的实体类

public class Wrapper implements Packing {

   @Override
   public String pack() {
      return "Wrapper";
   }
}

public class Bottle implements Packing {

   @Override
   public String pack() {
      return "Bottle";
   }
}

3、创建实现 Item 接口的抽象类,该类提供了默认的功能

public abstract class Burger implements Item {

   @Override
   public Packing packing() {
      return new Wrapper();
   }

   @Override
   public abstract float price();
}

public abstract class ColdDrink implements Item {

    @Override
    public Packing packing() {
       return new Bottle();
    }

    @Override
    public abstract float price();
}

4、创建扩展了 Burger 和 ColdDrink 的实体类

public class VegBurger extends Burger {

   @Override
   public float price() {
      return 25.0f;
   }

   @Override
   public String name() {
      return "Veg Burger";
   }
}

public class ChickenBurger extends Burger {

   @Override
   public float price() {
      return 50.5f;
   }

   @Override
   public String name() {
      return "Chicken Burger";
   }
}

public class Coke extends ColdDrink {

   @Override
   public float price() {
      return 30.0f;
   }

   @Override
   public String name() {
      return "Coke";
   }
}

public class Pepsi extends ColdDrink {

   @Override
   public float price() {
      return 35.0f;
   }

   @Override
   public String name() {
      return "Pepsi";
   }
}

5、创建一个 Meal 类,带有上面定义的 Item 对象

public class Meal {
   private List<Item> items = new ArrayList<Item>();    

   public void addItem(Item item){
      items.add(item);
   }

   public float getCost(){
      float cost = 0.0f;
      for (Item item : items) {
         cost += item.price();
      }     
      return cost;
   }

   public void showItems(){
      for (Item item : items) {
         System.out.print("Item : "+item.name());
         System.out.print(", Packing : "+item.packing().pack());
         System.out.println(", Price : "+item.price());
      }     
   }    
}

6、创建一个 MealBuilder 类,实际的 builder 类负责创建 Meal 对象

public class MealBuilder {

   public Meal prepareVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new VegBurger());
      meal.addItem(new Coke());
      return meal;
   }   

   public Meal prepareNonVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new ChickenBurger());
      meal.addItem(new Pepsi());
      return meal;
   }
}

7、BuiderPatternDemo 使用 MealBuider 来演示建造者模式(Builder Pattern )

public class BuilderPatternDemo {
   public static void main(String[] args) {
      MealBuilder mealBuilder = new MealBuilder();

      Meal vegMeal = mealBuilder.prepareVegMeal();
      System.out.println("Veg Meal");
      vegMeal.showItems();
      System.out.println("Total Cost: " +vegMeal.getCost());

      Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
      System.out.println("\n\nNon-Veg Meal");
      nonVegMeal.showItems();
      System.out.println("Total Cost: " +nonVegMeal.getCost());
   }
}

5、原型模式

简介:

  • 举例:

    • 跟MM用QQ聊天,一定要说些深情的话语了,我搜集了好多肉麻的情话,需要时只要copy出来放到QQ里面就行了,这就是我的情话prototype了。(100块钱一份,你要不要)
  • 原始模型模式:

    • 通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。
    • 原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。
    • 缺点是每一个类都必须配备一个克隆方法。
  • 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能

  • 何时使用:

    1. 当一个系统应该独立于它的产品创建,构成和表示时
    2. 当要实例化的类是在运行时刻指定时,例如,通过动态装载
    3. 为了避免创建一个与产品类层次平行的工厂类层次时
    4. 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
    5. 当直接创建对象的代价比较大时,则采用这种模式

适用场景:

  • 一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用
  • 细胞分裂
  • JAVA 中的 Object clone() 方法
  • 资源优化场景
  • 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等
  • 性能和安全要求的场景
  • 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
  • 一个对象多个修改者的场景
  • 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用
  • 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者
  • 原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用

结构:

image-20210411134012536

  1. 创建一个抽象类 Shape 和扩展了 Shape 类的实体类
  2. 定义类 ShapeCache ,该类把 shape 对象存储在一个 Hashtable 中,并在请求的时候返回它们的克隆
  3. PrototypPatternDemo 类使用 ShapeCache 类来获取 Shape 对象

代码实现:

1、创建一个实现了 Clonable 接口的抽象类 Shape

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

2、创建扩展了上面抽象类的实体类

public class Rectangle extends Shape {

   public Rectangle(){
     type = "Rectangle";
   }

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

public class Square extends Shape {

   public Square(){
     type = "Square";
   }

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

public class Circle extends Shape
{

   public Circle(){
     type = "Circle";
   }

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

3、创建类 ShapeCache,从数据库获取实体类,并把它们存储在一个 Hashtable

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

   // 对每种形状都运行数据库查询,并创建该形状
   // shapeMap.put(shapeKey, shape);
   // 例如,我们要添加三种形状
   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);
   }
}

4、PrototypePatternDemo 使用 ShapeCache 类获取存储在 Hashtable 中的形状的克隆

public class PrototypePatternDemo {
   public static void main(String[] args) {
      ShapeCache.loadCache();

      Shape clonedShape = (Shape) ShapeCache.getShape("1");
      System.out.println("Shape : " + clonedShape.getType());       

      Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
      System.out.println("Shape : " + clonedShape2.getType());      

      Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
      System.out.println("Shape : " + clonedShape3.getType());      
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值