设计模式-创建型

简介: 设计模式-创建型

设计模式-创建型


本章主要介绍有关对象创建的几种设计模式。


工厂模式


工厂模式:封装了对象的创建,使得获得对象更加符合实际逻辑


简单工厂

将所有对象的生产集中到一个工厂中

根据传参确定生产的对象类型

public abstract class Fruit { 
    private final String name;
    public Fruit(String name){
        this.name = name;
    }
    @Override
    public String toString() {
        return name+"@"+hashCode();
    }
}
public class Apple extends Fruit{  
    public Apple() {
        super("苹果");
    }
}
public class Orange extends Fruit{  
    public Orange() {
        super("橘子");
    }
}
public class FruitFactory {
    public static Fruit getFruit(String type) {
        switch (type) {
            case "苹果":
                return new Apple();
            case "橘子":
                return new Orange();
            default:
                return null;
        }
    }
}


缺点:

逻辑不符合:一个工厂一般只是单一生产

工厂设计不封闭:增加和减少生产对象需要对原来代码进行修改,不符合软件设计的开闭原则


工厂方法

将工厂划分成一个继承机构,基类工厂提供了生产对象虚函数接口,而派生类代表生产某种对象的工厂,重写基类提供的虚函数接口,返回生产的对象

public abstract class FruitFactory<T extends Fruit> {
    public abstract T getFruit();  
}
public class AppleFactory extends FruitFactory<Apple> {  
    @Override
    public Apple getFruit() {
        return new Apple();
    }
}


这样就可以使用不同类型的工厂来生产不同类型的水果了,并且如果新增了水果类型,直接创建一个新的工厂类就行,不需要修改之前已经编写好的内容。

缺点:

一个系列产品一个工厂结构,一种基类只能派生具有关联关系的生产工厂,不同类的需要构建其他的继承工厂结构

优点:

  1. 符合实际逻辑
  2. 符合开闭原则


抽象工厂

对有一组关联关系的产品簇提供产品的统一创建,即一个工厂生产一组相关联的产品

建立一个抽象工厂,一个实例工厂可以生产同一个产品簇的所有产品

public class Router {
}
public class Table {
}
public class Phone {
}
public abstract class AbstractFactory {
    public abstract Phone getPhone();
    public abstract Table getTable();
    public abstract Router getRouter();
}


所有的派生类需要重写所有的基类提供的虚函数接口

  • 总结:
  1. 简单工厂simple Factory :

优点:把对象的创建封装在一个接口函数里面,通过传入不同的标识,返回创建的对象,客户不用自己负责new对象,不用了解对象创建的详细过程

缺点:不符合实际生产逻辑,提供创建对象实例的接口函数不闭合,不能对修改关闭

  1. 工厂方法Factory Method:

优点:Factory基类,提供了一个纯虚函数(创建产品),定义派生类(具体产品的工厂)负责创建对应的产品(重写虚函数),可以做到不同的产品,在不同的工厂里面创建,能够对现有工厂,以及产品的修改关闭(符合软件开闭原则)

缺点:实际上,很多产品是有关联关系的,属于一个产品簇,不应该放在不同的工厂里面去创建,这样一是不符合实际的产品对象创建逻辑,二是工厂类太多了,不好维护

  1. 抽象工厂Abstract Factory:

把有关联关系的,属于一个产品簇的所有产品创建的接口函数,放在一个抽象工厂里面Abstract Factory,派生类(具体产品的工广)应该负责创建该产品簇里面所有的产品

所有派生类对基类提供的纯虚函数接口都要进行重写


建造者模式


有很多的框架都为我们提供了形如XXXBuilder的类型,一般可以使用这些类来创建我们需要的对象。

例如StringBuiler类:

public static void main(String[] args) {
    StringBuilder builder = new StringBuilder();   //创建一个StringBuilder来逐步构建一个字符串
    builder.append(666);   //拼接一个数字
    builder.append("老铁");   //拼接一个字符串
    builder.insert(2, '?');  //在第三个位置插入一个字符
    System.out.println(builder.toString());   //转换为字符串
}


通过建造者来不断配置参数或是内容,当我们配置完所有内容后,最后再进行对象的构建。

相比直接去new一个新的对象,建造者模式的重心更加关注在如何完成每一步的配置,如果一个类的构造方法参数过多,通过建造者模式来创建这个对象,会更加优雅。

案例:

public class Student {
    ...
    //一律使用建造者来创建,不对外直接开放
    private Student(int id, int age, int grade, String name, String college, String profession, List<String> awards) {
        ...
    }
    public static StudentBuilder builder(){   //通过builder方法直接获取建造者
        return new StudentBuilder();
    }
    public static class StudentBuilder{   //这里就直接创建一个内部类
        //Builder也需要将所有的参数都进行暂时保存,所以Student怎么定义的这里就怎么定义
        int id;
        int age;
        int grade;
        String name;
        String college;
        String profession;
        List<String> awards;
        public StudentBuilder id(int id){    //直接调用建造者对应的方法,为对应的属性赋值
            this.id = id;
            return this;   //为了支持链式调用,这里直接返回建造者本身,下同
        }
        public StudentBuilder age(int age){
            this.age = age;
            return this;
        }
        ...
        public StudentBuilder awards(String... awards){
            this.awards = Arrays.asList(awards);
            return this;
        }
        public Student build(){    //最后我们只需要调用建造者提供的build方法即可根据我们的配置返回一个对象
            return new Student(id, age, grade, name, college, profession, awards);
        }
    }
}


使用建造者来为生成学生对象:

public static void main(String[] args) {
    Student student = Student.builder()   //获取建造者
            .id(1)    //逐步配置各个参数
            .age(18)
            .grade(3)
            .name("小明")
            .awards("ICPC", "LPL")
            .build();   //最后直接建造我们想要的对象
}


单例模式

单例模式即在我们的整个程序中,同一个类始终只会有一个对象来进行操作。

饿汉单例:在一开始类加载时就创建好了

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();   //用于引用全局唯一的单例对象,在一开始就创建好
    private Singleton() {}   //不允许随便new,需要对象直接找getInstance
    public static Singleton getInstance(){   //获取全局唯一的单例对象
        return INSTANCE;
    }
}


懒汉单例:延迟加载,当我们需要获取对象时,才会进行检查并创建。

由于懒汉式是在方法中进行的初始化,在多线程环境下,可能会出现问题

public class Singleton {
    private static volatile Singleton INSTANCE;   //volatile保证线程可见性
    private Singleton() {} 
    public static Singleton getInstance(){
        if(INSTANCE == null) {//减低锁竞争
            synchronized (Singleton.class) {//保证线程安全
                if(INSTANCE == null) 
                    INSTANCE = new Singleton();  
            }
        }
        return INSTANCE;
    }
}


不用加锁懒汉模式:

public class Singleton {
    private Singleton() {}
    private static class Holder {   //由静态内部类持有单例对象,但是根据类加载特性,我们仅使用Singleton类时,不会对静态内部类进行初始化
        private final static Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance(){   //只有真正使用内部类时,才会进行类初始化
        return Holder.INSTANCE;   //直接获取内部类中的
    }
}


原型模式

原型模式实际上与对象的拷贝息息相关,原型模式使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象

  • **浅拷贝:**对于类中基本数据类型,会直接复制值给拷贝对象;对于引用类型,只会复制对象的地址。
  • **深拷贝:**无论是基本类型还是引用类型,深拷贝会将引用类型的所有内容,全部拷贝为一个新的对象,包括对象内部的所有成员变量,也会进行拷贝。

在Java中,通过实现Cloneable接口来实现原型模式:

Java为我们提供的clone方法对对象成员只会进行浅拷贝,要实现深拷贝需要进一步完成如何拷贝

public class Student implements Cloneable{
    String name;
    public Student(String name){
        this.name = name;
    }
    public String getName() {
        return name;
    }
    @Override
    public Object clone() throws CloneNotSupportedException   {   //针对成员变量也进行拷贝
        Student student = (Student) super.clone();
        student.name = new String(name);
        return student;   
    }
}


相关文章
|
5月前
|
设计模式
**工厂模式与抽象工厂模式**都是创建型设计模式,用于封装对象创建,减少耦合
【6月更文挑战第23天】**工厂模式与抽象工厂模式**都是创建型设计模式,用于封装对象创建,减少耦合。工厂模式专注于单个对象,通过具体工厂创建具体产品,适用于简单对象创建;抽象工厂则关注一系列相关产品,提供创建一族对象的接口,适用于处理多个不兼容产品族。选择模式基于问题域的复杂性,单个产品需求时用工厂模式,多产品族时用抽象工厂模式。
33 5
|
6月前
|
设计模式 搜索推荐 数据库连接
第二篇 创建型设计模式 - 灵活、解耦的创建机制
第二篇 创建型设计模式 - 灵活、解耦的创建机制
|
5月前
|
设计模式 Oracle Java
工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。
【6月更文挑战第20天】工厂模式简化对象创建,根据参数或条件生成MySQL或Oracle数据库连接。`DatabaseConnectionFactory`作为工厂,动态返回具体连接类型。装饰器模式则用于运行时动态增加对象功能,如`LoggingDecorator`为`Runnable`对象添加日志记录,保持代码整洁。在`Main`类中展示了如何使用这两种模式。
42 6
|
5月前
|
设计模式
创建型设计模式之建造者模式
创建型设计模式之建造者模式
|
6月前
|
设计模式 测试技术 Go
[设计模式 Go实现] 创建型~ 原型模式
[设计模式 Go实现] 创建型~ 原型模式
|
6月前
|
设计模式 测试技术 Go
[设计模式 Go实现] 创建型~工厂方法模式
[设计模式 Go实现] 创建型~工厂方法模式
|
6月前
|
设计模式 测试技术 Go
[设计模式 Go实现] 创建型~建造者模式
[设计模式 Go实现] 创建型~建造者模式
|
6月前
|
设计模式 JavaScript 前端开发
[设计模式Java实现附plantuml源码~创建型] 复杂对象的组装与创建——建造者模式
[设计模式Java实现附plantuml源码~创建型] 复杂对象的组装与创建——建造者模式
|
6月前
|
设计模式 缓存 架构师
创建型设计模式的比较与决策
本文深入探讨六种创建型设计模式:单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。通过概述各模式的核心概念、应用场景和关键要素,帮助读者理解并掌握这些模式的核心思想。文章还通过比较表和决策流程图,直观地展示了各模式之间的差异和选择依据,为读者提供了实用的设计模式选择指南。 本文的特色在于结合了理论与实践,每个模式都配有详细的代码示例和结构图,帮助读者更好地理解和应用这些模式。 总之,本文旨在为读者提供一篇全面、深入且实用的创建型设计模式指南,帮助读者在实际工作中灵活运用这些模式...
104 0
创建型设计模式的比较与决策
|
6月前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 对象的克隆~原型模式
[设计模式Java实现附plantuml源码~创建型] 对象的克隆~原型模式