首页 > 其他分享 >设计模式之创建型模式

设计模式之创建型模式

时间:2022-11-26 19:34:32浏览次数:42  
标签:return IdGenerator 创建 bytes 模式 new 设计模式 public String

创建型模式:提供创建对象的机制,提升已有代码的灵活性和 可复⽤性。

PS:博客根据it老齐大话设计模式课程课件进行整理,IT老齐 视频学习网站: https://www.itlaoqi.com

包含的设计模式:

  ⼯⼚⽅法模式、抽象⼯⼚模式、单例模式、建造者模式、原型模式

工厂模式

  根据需求提供创建对象的最佳方式;通过一个统一的接口创建所需对象,不对外暴露创建细节;

代码背景

  根据用户需求选择对应电脑

电脑接口类

public interface Computer {
public String describe(); }

外星人电脑类

public class Alienware implements Computer{
  @Override
  public String describe() {
    return "外星⼈ALIENWARE m15 R7 15.6英⼨⾼端游戏本 12代i7 32G RTX3060 QHD 240Hz ⾼刷屏 轻薄笔记本电脑2765QB";
  }
}

办公轻薄本类

public class Macbook implements Computer{
  @Override
  public String describe() {
    return "Apple MacBook Pro 13.3 ⼋核M1芯⽚ 8G 256G SSD 深空灰 笔记本电脑 轻薄本 MYD82CH/A";
  }
}

注意:如果我们让客户自己来选择电脑,把控制权交易客户是不对的,因为这样就破坏“迪⽶特法则”,所以选择权交还给电脑店这⼀⽅。

工厂类

  帮助顾客进⾏决策,这样控制权掌握

public class ShopFactory {
  public Computer suggest(String purpose){
    Computer computer = null;
    if(purpose.equals("⽇常办公")){
      return new Macbook();
    }else if(purpose.equals("3A游戏")){
      return new Alienware();
    }
    return computer;
  }
}

顾客操作类

public class Customer {
  public static void main(String[] args) {
    ShopAssistant shopAssistant = new ShopAssistant();
    Computer c = shopAssistant.suggest("3A游戏");
    System.out.println(c.describe());
  }
}

结论:使用工厂模式来创建所需对象,可以很好的降低调用者和程序之间的耦合,使得调用者在不需要知道过多信息的情况下获取到符合需求的操作对象;

 

抽象工厂模式

  顾名思义即为⼯⼚的⼯⼚,通过构建顶层的抽象⼯⼚和抽象的产品,屏蔽系列产品的构建过程

代码背景

  公司早期接⼊七⽜云OSS(对象存储服务)上传图⽚与视频,后因业务调整,公司要求额外⽀持阿⾥ 云、腾讯云等其他云服务商,并且可以对客户提供外界访问,现需要在不破坏原有代码逻辑情况下,实现对任意三⽅云⼚商的接⼊。

图片接口类

public interface OssImage {
  public String getThumb() ;
}

视频接口类

public interface OssVideo {public String get1080P();
}

抽象工厂类

import OssImage;
import OssVideo;
public interface AbstractOssFactory {
  public OssImage uploadImage(byte[] bytes);
  public OssVideo uploadVideo(byte[] bytes);
}

七牛云实现

工厂实现类

import AbstractOssFactory;
import OssImage;
import OssVideo;
import QiniuOssImage;
import QiniuOssVideo;
public class QiniuOssFactory implements AbstractOssFactory {
  @Override
  public OssImage uploadImage(byte[] bytes) {
    return new QiniuOssImage(bytes,"IT⽼⻬");
  }
  @Override
  public OssVideo uploadVideo(byte[] bytes) {
    return new QiniuOssVideo(bytes,"IT⽼⻬");
  }
}

七牛云图片实现类

import OssImage;
public class QiniuOssImage implements OssImage {
  private byte[] bytes;
  public QiniuOssImage(byte[] bytes,String watermark){
    this.bytes = bytes;
    System.out.println("[七⽜云]图⽚已上传⾄七⽜云OSS,URL:http://oss.qiniu.com/xxxxxxx.jpg");
  }
  @Override
  public String getThumb() {
    return "http://oss.qiniu.com/xxxxxxx_thumb.jpg";
  }
}

七牛云视频实现类

import OssVideo;
public class QiniuOssVideo implements OssVideo {
  private byte[] bytes;
  public QiniuOssVideo(byte[] bytes, String watermark) {
    this.bytes = bytes;
    System.out.println("[七⽜云]视频已上传⾄阿⾥云OSS,URL:http://oss.qiniu.com/xxx.mp4");
 }
  @Override
  public String get1080P() {
    return "http://oss.qiniu.com/xxx_1080p_3500.mp4";
  }
}

阿里云实现

阿里云工厂

import AbstractOssFactory;
import OssImage;
import OssVideo;
import AliyunOssImage;
import AliyunOssVideo;
public class AliyunOssFactory implements AbstractOssFactory {
  @Override
  public OssImage uploadImage(byte[] bytes) {
    return new AliyunOssImage(bytes,"IT⽼⻬",true);
  }
  @Override
  public OssVideo uploadVideo(byte[] bytes) {
    return new AliyunOssVideo(bytes,"IT⽼⻬");
  }
}

阿里云图片实现类

import OssImage;
public class AliyunOssImage implements OssImage {
  private byte[] bytes;
  public AliyunOssImage(byte[] bytes, String watermark,boolean transparent){
    this.bytes = bytes;
    System.out.println("[阿⾥云]图⽚已上传⾄阿⾥云OSS,URL:http://oss.aliyun.com/xxxxxxx.jpg");
  }
  @Override
  public String getThumb() {
    return "http://oss.aliyun.com/xxxxxxx_thumb.jpg";
  }
}

阿里云视频实现类

import OssVideo;
public class AliyunOssVideo implements OssVideo {
  private byte[] bytes;
  public AliyunOssVideo(byte[] bytes, String watermark) {
    this.bytes = bytes;
    System.out.println("[阿⾥云]视频已上传⾄阿⾥云OSS,URL:http://oss.aliyun.com/xxx.mp4");
  }
  @Override
  public String get1080P() {
    return "http://oss.aliyun.com/xxx_1080p.mp4";
  }
}

客户调用类

import AliyunOssFactory;
import AbstractOssFactory;
import OssImage;
import OssVideo;
import QiniuOssFactory;
public class Client {
  public static void main(String[] args) {
    // AbstractOssFactory factory = new AliyunOssFactory();
    AbstractOssFactory factory = new QiniuOssFactory();
   OssImage ossImage = factory.uploadImage(new byte[1024]); OssVideo ossVideo = factory.uploadVideo(new byte[1024]); System.out.println(ossImage.getThumb()); System.out.println(ossImage.getWatermark()); System.out.println(ossImage.getEnhance()); System.out.println(ossVideo.get720P()); System.out.println(ossVideo.get1080P()); } }

结论:抽象工厂模式,在工厂模式的基础上进行一层抽象,在工厂之上建立一个总工厂,用户可以通过总工厂来创建指定类型的子工厂来实现自己的操作;抽象工厂模式和与⼯⼚模式⼀样,都是⽤来解决接⼝选择的问题;

 

单例模式

  ⼀个类只允许创建⼀个对象(或者实例),这种设计模式就叫作单例设计模式,简称单例模式。

单例模式的创建方式

  饿汉式,懒汉式,静态内部类,枚举

饿汉式

  类加载时直接实例化单例对象

public class IdGenerator {
  private AtomicLong id = new AtomicLong(0);
  private static final IdGenerator instance = new IdGenerator();
  private IdGenerator() {}
  public static IdGenerator getInstance() {
    return instance;
  }
  public long getId() {
    return id.incrementAndGet();
  }
}

缺点:不⽀持延迟加载,如果实例占⽤资源多(⽐如占⽤内存多)或初始化 耗时⻓(⽐如需要加载各种配置⽂件),提前初始化实例是⼀种浪费资源的⾏为

懒汉式

  第⼀次调⽤时实例化对象(延迟加载)

public class IdGenerator {
  private AtomicLong id = new AtomicLong(0);
  private static IdGenerator instance;
  private IdGenerator() {}
  public static synchronized IdGenerator getInstance() {
    if (instance == null) {
      instance = new IdGenerator();
    }
    return instance;
  }
  public long getId() {
    return id.incrementAndGet();
  }
}

缺点:synchronized会使得这个函数的并发度很低,如果频繁地⽤到,那频繁加锁、释放锁会导致性能瓶颈

懒汉式-双重校验

  加锁之前先进行一次判断,满足条件直接返回,从而减少频繁加锁问题

public class IdGenerator {
  private AtomicLong id = new AtomicLong(0);
  private static IdGenerator instance;
  private IdGenerator() {}
  public static IdGenerator getInstance() {
    if (instance == null) {
      synchronized(IdGenerator.class) { // 此处为类级别的锁
        if (instance == null) {
          instance = new IdGenerator();
        }
      }
    }
    return instance;
  }
  public long getId() {
    return id.incrementAndGet();
  }
}

缺点:在低版本的java中,存在指令重排序的问题,从而导致 IdGenerator 对象被 new 出来

静态内部类

  通过静态内部类的方式创建对象,点类似饿汉式,但⼜能做到了延迟加载

public class IdGenerator {
  private AtomicLong id = new AtomicLong(0);
  private IdGenerator() {}
  private static class SingletonHolder{
    private static final IdGenerator instance = new IdGenerator();
  }
  public static IdGenerator getInstance() {
    return SingletonHolder.instance;
  }
  public long getId() {
    return id.incrementAndGet();
  }
}

分析:内部类在外部类被加载时是不会创建的,只有调用 getInstance() ⽅法时,内部类才会被加载并且会创建 instance,instance 的唯⼀性、创建过程的线程安全性,都由JVM来保证,这种方式既保证了线程安全,⼜能做到延迟加载

枚举

  基于枚举类型的单例实现。这种实现⽅式通过 Java枚举类型本身的特性,是最简单实现单例的⽅式,保证了实例创建的线程安全性和实例的唯⼀性

public enum IdGenerator {
 INSTANCE;
  private AtomicLong id = new AtomicLong(0);
  public long getId() {
    return id.incrementAndGet();
  }
  public static void main(String[] args) {
    IdGenerator instance = IdGenerator.INSTANCE;
    System.out.println(instance.getId());
  }
}

注意:枚举方式创建的对象能做到真正的单例,其他几种方式创建的单例对象会被反射和序列化的方式破坏单例

反射破坏单例

import java.lang.reflect.Constructor;  
import java.lang.reflect.InvocationTargetException;    
public class ReflectAttack  
{
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException  
    {  
        Class<?> classType = IdGenerator.class; 
        Constructor<?> c = classType.getDeclaredConstructor(null);  
        c.setAccessible(true);  
        IdGenerator e1 = (IdGenerator)c.newInstance();  
        IdGenerator e2 = IdGenerator.getInstance();  
        System.out.println(e1==e2);  
    }
}

注意:输出结果为false,说明e1和e2不是同一个对象,单例被破坏。

序列化破坏单例

这里IdGenerator类要实现一下Serializable类,不然无法序列化

public static void main(String[] args) throws IOException, ClassNotFoundException  
{ IdGenerator e1= null; IdGenerator e2 = IdGenerator.getInstance(); FileOutputStream fos = new FileOutputStream("IdGenerator.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(e2); oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("IdGenerator.obj"); ObjectInputStream ois = new ObjectInputStream(fis); e1 = (IdGenerator)ois.readObject(); System.out.println(e2==e1);
}

注意:输出结果为false,说明e1和e2不是同一个对象,单例被破坏。

 

建造者模式

  摆脱超⻓构造⽅法参数的束缚的同时也保护了”不 可变对象“的密闭性

格式

  ⽬标类的构造⽅法要求传⼊Builder对象

  Builder建造者类位于⽬标类内部且⽤static描述

  Builder建造者对象提供内置属性与各种set⽅法,注意set⽅法返回 Builder对象本身

  Builder建造者类提供build()⽅法实现⽬标类对象的创建

Builder

public class ⽬标类(){
  //⽬标类的构造⽅法要求传⼊Builder对象
  public ⽬标类(Builder builder){
  }
 
  public 返回值 业务⽅法(参数列表){
   //doSth
  }
  //Builder建造者类位于⽬标类内部且⽤static描述
  public static class Builder(){
    //Builder建造者对象提供内置属性与各种set⽅法,注意set⽅法返回Builder对象本身
    private String xxx ;
    public Builder setXxx(String xxx) {
    this.xxx = xxx;
      return this;
    }
 
    //Builder建造者类提供build()⽅法实现⽬标类对象的创建
    public ⽬标类 build() {
      //业务校验
      return new ⽬标类(this);
     }
  }
}

注意:Builder类中的属性最好有初始值,这样在调用时,可以减少属性未赋值的错误,或者在调用build()时加以判断说明

 

原型模式

  ⽤⼀个已经创建的实例作为原型,通过复制该原型对象来创建⼀个和原型相同或相似的新对象;原型实例指定了要创建的对象的种类。⽤这种⽅式创建对象⾮常⾼效,根本⽆须知道对象创建的细节。

优点

  Java ⾃带的原型模式基于内存⼆进制流的复制,在性能上⽐直接 new ⼀个对象更加优良

  可以使⽤深克隆⽅式保存对象的状态,使⽤原型模式将对象复制⼀份,并将其状态保存起来,简化了 创建对象的过程,以便在需要的时候使⽤(例如恢复到历史某⼀状态),可辅助实现撤销操作。

缺点

  需要为每⼀个类都配置⼀个 clone ⽅法

  clone ⽅法位于类的内部,当对已有类进⾏改造的时候,需要修改代码,违背了开闭原则。

   当实现深克隆时,需要编写较为复杂的代码,⽽且当对象之间存在多重嵌套引⽤时,为了实现深克 隆,每⼀层对象对应的类都必须⽀持深克隆,实现起来会⽐较麻烦。因此,深克隆、浅克隆需要运⽤得当。

应用场景

  对象之间相同或相似,即只是个别的⼏个属性不同的时候。

  创建对象成本较⼤,例如初始化时间⻓,占⽤CPU太多,或者占⽤⽹络资源太多等,需要优化资源。

  创建⼀个对象需要繁琐的数据准备或访问权限等,需要提⾼性能或者提⾼安全性。

  系统中⼤量使⽤该类对象,且各个调⽤者都需要给它的属性重新赋值。

浅克隆与深克隆

浅克隆

  创建⼀个新对象,新对象的属性和原来对象完全相同,对于⾮基本类型属性,仍指向原有属性 所指向的对象的内存地址

public class Employee implements Cloneable{
  private String name;
  private Car car;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Car getCar() {
    return car;
  }
  public void setCar(Car car) {
    this.car = car;
  }
 //重写Clone⽅法
  @Override
  protected Object clone() throws CloneNotSupportedException {
  System.out.println("正在复制Employee对象");
    return super.clone();
  }
}

注意:Employee类中有一个Car这个非基本类型的属性,当克隆Employee类时,克隆类中的Car属性和原始类中的Car属性指向的内存地址是同一块,这样会导致在原始类中修改Car属性中的数据,克隆类中Car属性中的值也会发生变化

深克隆

  深克隆:创建⼀个新对象,属性中引⽤的其他对象也会被克隆,不再指向原有对象地址,一般基于Json实现对象深度Clone,不再需要实现Clonable接⼝与clone()⽅法

import com.google.gson.Gson;
public class Employee{
  private String name;
  private Car car;
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public Car getCar() {
    return car;
  }
 
  public void setCar(Car car) {
    this.car = car;
  }
  //基于JSON实现深度序列化
  public Employee deepClone(){
    Gson gson = new Gson();
    String json = gson.toJson(this);
    System.out.println(json);
    Employee cloneObject = gson.fromJson(json, Employee.class);
    return cloneObject;
  }
}

标签:return,IdGenerator,创建,bytes,模式,new,设计模式,public,String
From: https://www.cnblogs.com/caixiaozi/p/16927910.html

相关文章

  • 解释器模式(Interpreter)
    自定义解析器。需要:构建语法树,定义终结符与非终结符。 替代方案:Java中使用脚本引擎运行脚本语言......
  • 访问者模式(Visitor)
    表示一个作用于某对象结构中的各个元素的操作,使我们在不改变元素的类的前提下定义作用于这些元素的新操作。使用场景:对象结构比较稳定,但经常需要在此对象结构上定义新的......
  • 外观模式(也叫做门面模式)
    外观模式(也叫做门面模式):影院管理项目:         外观模式的基本介绍:   外观模式的原理类图:   原理类图的说明(外观模式的角色)1)外观类(F......
  • 命令模式(Command)
    将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。 结构:......
  • 企业办公新模式,随时随地云上协同!
    如今,越来越多人参与到项目中进行协同,因此对企业内部的协同办公提出了更高的要求,同时加之大环境下的居家办公要求,导致很多人一回到家之后就会出现无电脑可用、没有办公室电脑......
  • 【Amadeus原创】vmware ESXi快速创建新的虚拟机
    准备工作:新虚拟机Win10安装后,需要windowsupdate,更新补丁到最新,关机。(本文案例win10-Amadeus)在数据盘新建Win10-Users文件夹(可自定义)复制win10-Amadeus的vmx、vmdk文件到wi......
  • D110设计模式_4备忘录模式20221122
     备忘录模式(MementoPattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。客户不与备忘录类耦合,与备忘录管理类耦合。优点: 1、给用......
  • Python中创建类的六重境界
    1.引言大家首先需要记住一句话:类是模板,而实例则是根据类创建的对象。在面向对象编程语言中,类class最为常见。为此,本文重点来介绍在Python中创建类的六重境界。闲话少说,我......
  • 中介者模式(Mediator )
    用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。场景:公司多个部门之间,若直接互相打交......
  • 迭代器模式(Iterator)
    用来遍历集合的工具。实现方式:使用一个游标记录当前读取位置。容器中使用迭代器:   一般迭代器都有的方法,整个接口:publicinterfaceMyInterator{......