创造型模式
创建模式分成五种模式
- 单例模式
- 工厂模式
- 抽象工厂模式
- 建造者模式
- 原型模式
设计模式总结前言:
设计模式是软件开发过程中的基础,是针对软件设计过程中经常出现的问题提供一个典型的解决方案。我们可以将之称之为一种固定的问题的特定的解决的方案,软件的设计模式是一种思想,他没有提供一种特定的代码片段,而是提供了一种设计的思想,这些思想能够改变我们的开发思想,以及优化我们的产品,缩短我们在开发中存在的一些问题。
设计模式学习网站:
1. 单例模式
前言:
初开始的时候,会感觉单例模式的主要问题是需要解决多线程的问题,但是在编译期的时候构建对象的方法,需要考虑到类加载的问题,于是饿汉单例模式出现,但是发现线程太多了,会突破单检索模型,后来引入了双检索模型,还有具体的volatile的计划,当然看似进展的没有问题,这时候需要考虑的是人们自身上的问题,反射破坏。
单例模式的要求:
确保一个类只有一个实例,而且自行实例化并且向整个系统提供这个实例。
【重点】:
程序运行的过程中一个类只能够创建一个对象
构造器私有化
调用静态的方法获取对象
【应用场景】
同时如果创建某个对象需要消耗较多的资源的话,比如IO 或者是数据库资源的时候,我们可以使用单例模式来减少资源的消耗.
1.windows中的任务管理器、回收站
2.项目中读取配置文件的类
3.网站的计数器
4.Spring中,每一个Bean默认都是单例的
5.servlet编程中,每一个servlet中都是单例存在的。
6.Spring MVC 中,控制器都是单例的存在
1.1. 饿汉式
专业:类初始化的时候,会立即记载该对象,线程天生安全,调用率比较高。
理解:不管不顾,上来就new对象
/**
* @author sky
* 单例模式:其中最为重要的是两个一个是饿汉模式一个是懒汉模式
*/
public class Sun {
/**
* 创建自我独有的单例,自己创建自己
* private关键字确保:实例的私有化操作,不可见性和不可访问的特性;
* static:确保太阳的静态化操作,将太阳放在内存里的静态区中,在类加载的时候进行了初始化操作,该实例会在内存中和类一起永生
* final:确保这个太阳的地址,一旦被赋值就不能够被修改,等同于房产,一旦进行赋值操作就不能再动了
* new关键字初始化静态的实例
* 总结:在初始化的阶段就主动进行实例化操作,犹如饿汉所以就是饿汉模式
*/
private static final Sun sun = new Sun();
/**
* 构造方法私有化操作,将此类进行完全的封印,外界无法通过创建对象的方式访问此类
*/
private Sun() {
System.out.println("Sun 对象私有构造方法");
}
/**
* 将方法进行公开化,对于外部来说,只需要调用 Sun.getSun() 就能够得到太阳的对象了,并且不管是是谁得到,或者说得到几次,
* 得到的都是同一个对象实例,这样就能够确保太阳的唯一合法性操作。
*
* @return 阳光普照
*/
public static Sun getSun() {
System.out.println("调用Sun方法,实现太阳的东升");
return sun;
}
/**
* 检验单例模型的饿汉模式
*/
public static void main(String[] args) {
Sun sun = Sun.getSun();
Sun sun1 = Sun.getSun();
/**
* 判断sun 和 sun1 是否是同一个对象实例
*/
if (sun1.equals(sun)) {
System.out.println("初次判断比较的是地址一致");
}
}
}
运行结果:
Sun 对象私有构造方法
调用Sun方法,实现太阳的东升
调用Sun方法,实现太阳的东升
初次判断比较的是地址一致
根据结果分析,不管什么情况,上来先创建一个实例对象。
1.2 懒汉式
专业:调用方法时实例化,多线程应用中有安全隐患,防止出现多线程的同步执行,。
解说:饿汉模式的上来就创建对象,容易造成内存浪费。根据市场的供需关系,啥时候需要啥时候生产的模式,规定某些商品必须提前预定,这就是懒汉模式。
初次改造
改动地点:
// 不在进行赋值的操作,因为第一开始没有创建太阳实例,所以去除关键字final
private static Sun sun;
//如果没有太阳,则进行太阳的创造
public static Sun getSun() {
if (sun == null) {
sun = new Sun();
}
return sun;
}
出现的问题:在多线程的模式下操作,是会存在缺陷的,试想一下如果是并发请求的操作,判空的逻辑就会同时成立,这就会造成创建多个单例模式,这时候我们可以追加上同步锁的概念。这样就会让线程调用的时候必须获取同步锁,调用完成之后会释放锁给其他的线程使用,也就是请求排队。
private static Sun sun;
public static synchronized Sun getSun() {
if (sun == null) {
sun = new Sun();
}
return sun;
}
出现的问题: 线程还没有进入到方法内部,便开始进行加锁排队等候,会造成线程的阻塞,资源与时间进行白白的浪费。我们只是为了进行实例化一个单例对象,所以可以改正加锁的位置。
private static Sun sun;
public static Sun getSun() {
/**
* 观日台的入口
*/
if (sun == null) {
//观日台进行排队
synchronized (Sun.class){
if (sun == null) {
// 最头的人造出了太阳,实现太阳的东升操作。
sun = new Sun();
}
}
}
// 阳光普照,其余的不能够再造太阳
return sun;
}
总结:在程序中我们使用到了两个嵌套式的判断方式,这就是懒加载中的 双检索 ,外层放宽入口,保证线程并发的高效性;内层加入锁同步,保证实例化的单词运行。
关键字:volatile对于静态变量的修饰则能够保证变量的值在各个线程访问时间的同步性、唯一性。
相比较懒汉模式,在大多数的情况下,我们仍然是采用饿汉模式的操作方法,原因是这个单例迟早是被进行实例化的操作,延迟懒加载的意义并不是特别的大,加锁解锁的方式反而是一种资源的浪费,同步更是会降低CPU的利用效率,大道至简。
单例防止反射漏洞攻击,更改程序段。
private static boolean flag = false;
/**
* 构造方法私有化操作,将此类进行完全的封印,外界无法通过创建对象的方式访问此类
*/
private Sun() {
if (flag == false){
flag = !flag;
}else {
throw new RuntimeException("单例模式被侵犯");
}
System.out.println("Sun 对象私有构造方法");
}
1.3 单例模式的优点
1.单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源的时候,如果读取配置,产生其他的依赖对象的时候,则可以通过在应用启动的时候直接产生一个单例对象,然后永久驻留内存的方式来解决。
2.单例模式可以在系统设置全局访问点,优化共享资源的访问,例如可以设计一个单例类,负责所有数据表的映射处理。
1.4 单例模式的缺点
1.不适合用于变化的对象,如果同一个类型的对象总是要在不同的用例场景发生变化,单例会引起数据的错误,不能保存彼此的状态
2.由于单例模式模式中没有抽象层,因此单例类的扩展性有很大的困难。
3.单例类的职责过于重要, 在一定的程度上违背了 单一职责原则。
4.滥用单例将带来一些负面的问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接对象的程序过多出现的连接池溢出;如果实例化的对象长时间不会被利用,系统会认为是垃圾而被回收操作,这将导致对象状态的丢失。
2.工厂模式
在工厂模式中,我们在创建对象的时候,不会对于客户端暴露创建逻辑,并且通过使用一个共同的接口来指向新创建的对象,实现创建者和调用者分离的操作。
核心:
1.实例化对象不能够使用new,而是通过工厂方法来实现的。
2.将选择实现类,创建对象统一管理和控制,从而调用者跟我们的实现类解耦合
2.1 简单工厂模型
简单工厂模型:相当于工厂中有各种产品,创建在一个类中,客户不需要支持具体的产品的名称,只需要知道产品类所对应的参数即可,但是工厂的职责过重,不利于系统的拓展需要。
- 创建工厂产品类:
创建汽车类接口
/**
* @author 法外狂徒张三
* @package_name:cn.design.Factory
* @des:创建产品类
*/
public interface Car {
/**
* 功能,产品的运行操作,接口中的方法的缺省参数是public static abstract
*/
public abstract void run();
}
- 创建工厂的产品一:
通过接口实现,产品一
/**
* @author 法外狂徒张三
* @package_name:cn.design.Factory
* @des:
*/
public class BMW implements Car{
@Override
public void run() {
System.out.println("宁愿在宝马车上哭,不愿在自行车上笑");
}
}
- 创建工厂的产品二:
创建工厂产品二奔驰商品
/**
* @author 法外狂徒张三
* @package_name:cn.design.Factory
* @des:
*/
public class Benz implements Car{
@Override
public void run() {
System.out.println("宁愿在奔驰车上哭,不愿在自行车上笑");
}
}
- 创建核心的工厂类:负责创建对象:
/**
* @author 法外狂徒张三
* @package_name:cn.design.Factory
* @des:创建核心的工厂类
* 主要的功能:扶着创建生产对象操作
*/
public class CarFactory {
/**
* 主要的功能是你告诉我生产什么我生产什么
*/
/**
* 根据名字创建对象
*
* @param name 需要生产的汽车的名字
* @return 返回的是生产的对象
*/
public static Car creatCar(String name){
if (name.equals("")) {
return null;
}else if(name.equals("宝马")){
return new BMW();
}else if (name.equals("奔驰")){
return new Benz();
}else {
return null;
}
}
}
- 检测演示操作:
/**
* @author 法外狂徒张三
* @package_name:cn.design.Factory
* @des:
*/
public class Main {
public static void main(String[] args) {
Car benz = CarFactory.creatCar("奔驰");
Car bmw = CarFactory.creatCar("宝马");
benz.run();
bmw.run();
}
}
运行的结果:
宁愿在奔驰车上哭,不愿在自行车上笑
宁愿在宝马车上哭,不愿在自行车上笑
2.1.1 简单工厂的优点
简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪一个具体的对象。明确区分了各自的职责和权力,有利于整个软件的体系结构的优化
2.1.2 简单工厂的缺点
很明显工厂类集中了所有实例的创建逻辑,再进行内容的添加,容易违反开放闭合原则。
2.2 工厂方法模型
标准概念:工厂方法模型:又称为多态性工厂模型。在工厂方法模型中**,核心的工厂不在负责所有的产品的创建,而是将具体创建的工作交给子类去做**。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一种产品类应当被实例化这个细节。
帮助理解:工厂方法的模式实际上是在简单工厂模式的基础之上,将原有的工厂类,进行处理,不在通过工厂类直接创建子类,而是通过封装,将其创建交给接口的实现类进行操作,也就是字面上的子类。当然注意和上述的简单方法的对比。
- 创建汽车接口
public interface Car {
void run();
}
- 宝马汽车运行实现
public class Bmw implements Car{
@Override
public void run() {
System.out.println("宝马车的实现操作");
}
}
- 奔驰汽车运行实现
public class Benz implements Car{
@Override
public void run() {
System.out.println("奔驰车的正常运行操作");
}
}
- 创建汽车工厂接口
public interface CarFactory {
/**
* 创建对象的方法,返回值的类型是Car对象
* @return
*/
Car createCar();
}
- 创建具体奔驰汽车实现类
public class BenzFactory implements CarFactory{
@Override
public Car createCar() {
return new Benz();
}
}
- 创建具体宝马汽车实现类
public class BmwFactory implements CarFactory{
@Override
public Car createCar() {
return new Bmw();
}
}
- 测试类:根据自己的需求,直接联系对应的汽车工厂
public class MainTest {
public static void main(String[] args) {
/**
* 需要那一辆车,直接找到对应的工厂进行生产操作
*/
Car car = new BenzFactory().createCar();
Car car1 = new BmwFactory().createCar();
car.run();
car1.run();
}
}
3.抽象工厂模式
3.1 抽象工厂模式的概念
抽象工厂模式提供了一种可能性,可以将一组具有同一个主题的单独的工厂封装起来 ,抽象工厂简单的来说就是工厂的工厂,抽象工厂可以创建具体的工厂,由具体工厂来产生具体的产品。
3.2 抽象工厂模式的实现
- 创建Car接口
public interface Car {
void run();
}
- 创建宝马汽车实现类
public class Bmw implements Car{
@Override
public void run() {
System.out.println("宝马车运行正常");
}
}
- 创建奔驰汽车实现类
public class Beaz implements Car{
@Override
public void run() {
System.out.println("奔驰车正常运行");
}
}
- 创建Engine接口
public interface Engine {
void run();
}
- 创建引擎一实现类
public class EngineA implements Engine{
@Override
public void run() {
System.out.println("A引擎转的速度比较快");
}
}
- 创建引擎二实现类
public class EngineB implements Engine{
@Override
public void run() {
System.out.println("运行速度慢");
}
}
- 创建总工厂接口
public interface TotalFactory {
/**
* 对于总工厂的实现
*/
Car creatCar();
Engine creatEngine();
}
- 创建总工厂实现类
public class TotalFactoryImpl implements TotalFactory{
@Override
public Car creatCar() {
return new Beaz();
}
@Override
public Engine creatEngine() {
return new EngineA();
}
}
- 实现类操作
public class Main {
public static void main(String[] args) {
/*
创建总工厂的模式
*/
TotalFactoryImpl totalFactory = new TotalFactoryImpl();
/**
* 创建一个奔驰车,并且进行测试跑动
*/
Car car = totalFactory.creatCar();
car.run();
/**
* 创建引擎一,并且进行引擎的检测
*/
Engine engine = totalFactory.creatEngine();
engine.run();
}
}
运行结果:
奔驰车正常运行
A引擎转的速度比较快
3.3 抽象工厂模式的总结
当定义一个具有相同特性的类的时候,只需要修改工厂类。创建多个工厂类而不是一个工厂类,一旦需要创建新的类对象,只需要增加新的工厂类型就可以了,不需要修改之前的代码,如此就可以较好的解决工厂方法模式的问题。
4.建造者模式
4.1 概述
4.1.1 问题
现在提出一个需求,需要建造一个房子。
abstract class Bulider {
/**
* 创建一个房子需要,地基、墙、屋顶、门、窗户
*/
/**
* 建造地基
*/
abstract void buildBase();
/**
* 建造墙壁
*/
abstract void buildWall();
/**
* 建造屋顶
*/
abstract void buildRoof();
/**
* 建造屋顶
*/
abstract void buildDoor();
/**
* 建造窗户
*/
abstract void buildWindow();
/**
* 得到产品
*/
abstract Product getResult();
}
4.1.2解决方案
这里现在有两个解决方法,一种是创建很多不同参数的构造方法(折叠构造函数模式),来满足不同的需求,但是这样灵活性较差;第二种是使用JavaBean,setter方法实例化对象。这里的属性设置是分开的,如果参数过多,很可能会出现遗漏和出错的情况。
4.2 实现
4.2.1 分析
场景分析:
建造者模式建议将对象构造代码从产品中抽取出来,并将其放在一个名为生成器的独立的对象中。
将建造房子拆分,每个部分建造的东西不同,然后组合到一起生成一个完整的部分。
结构的分析:
- Product`: 最终要生成的对象,例如 House实例。
Builder
: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,(构建房子的步骤)其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()。ConcreteBuilder
(具体建造者): Builder的实现类。Director(指导者)
: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct()方法获得最终的产品。
// 接口
public interface Builder {
/**
* 创建一个房子需要,地基、墙、屋顶、门、窗户
*/
/**
* 建造地基
*/
void buildBase();
/**
* 建造墙壁
*/
void buildWall();
/**
* 建造屋顶
*/
void buildRoof();
/**
* 建造屋顶
*/
void buildDoor();
/**
* 建造窗户
*/
void buildWindow();
/**
* 创建商品,最终的目的是为了创建商品
* @return
*/
Product getResult();
}
//Direct
public class Diretor {
public void build(Builder builder){
System.out.println(builder);
// 给出要求,需要创建的部分
builder.buildBase();
builder.buildDoor();
builder.buildRoof();
builder.buildWall();
builder.buildWindow();
}
}
//Product
public class Product {
/*
* 作用是通过创建的部分组成一个完整的商品
*/
// 创建集合用于内容的拼接操作
ArrayList<String> list = new ArrayList<>();
/**
* 将生产的部分,组装成为一个完整的整体
*
* @param part 传入需要生产的东西
*/
public void add(String part){
list.add(part);
}
/** 将生产的东西展示出来
*
*/
public void show(){
System.out.println("产品生成结束");
for (String s : list) {
System.out.println(s);
}
}
}
// 建造指定的建造者
public class BuilderFirst implements Builder{
// 引入商品对象,没有实例化对象,所以存在空指针
private Product product = new Product();
@Override
public void buildBase() {
product.add("建造地基");
}
@Override
public void buildWall() {
product.add("建造外墙");
}
@Override
public void buildRoof() {
product.add("建造屋顶");
}
@Override
public void buildDoor() {
product.add("建造屋顶");
}
@Override
public void buildWindow() {
product.add("建造房顶");
}
@Override
public Product getResult() {
return product;
}
}
// 测试
public class Test {
public static void main(String[] args) {
// 创建指挥者对象
Diretor diretor = new Diretor();
//创建需要呈现的对象
BuilderFirst builderFirst = new BuilderFirst();
//指挥者使用对象 创建产品
diretor.build(builderFirst);
Product result = builderFirst.getResult();
result.show();
}
}
4.3 总结
4.3.1 概念
建造者模式是一种创建型的设计模式,也叫做生成器的模式,用户只需要指定需要建造的类型就可以得到该类型对应的产品的实例,不用关心建造的过程细节,实际上就是构建包含多个组件的对象,采用相同的构建过程,创建不同的产品。
4.3.2 优点
- 降低耦合性:建造者模式可以将对象的创建与使用分离,降低了对象之间的耦合性,使得系统更加灵活、易于维护和扩展。
- 增加可读性:使用建造者模式可以将复杂对象的创建过程分解为多个简单的步骤,使得代码更加清晰、易于理解和维护。
- 提高灵活性:通过建造者模式可以使用相同的创建过程来创建不同类型的对象,从而提高了系统的灵活性。
- 可以控制对象的创建过程:建造者模式可以控制对象的创建过程,从而可以根据需要对创建过程进行优化和调整,提高对象的性能和质量。
4.3.3 缺点
- 建造者模式的实现较为复杂,需要定义多个类和接口,因此增加了系统的复杂性。
- 如果对象较为简单,使用建造者模式可能会导致代码冗余,降低代码的可读性和可维护性。
- 对象创建过程一旦开始就无法中途取消或修改,因此建造者模式不适用于需要动态调整对象创建过程的场景。
4.3.4 工厂模式和建造者模式的对比
- 建造者模式和工厂模式的不同点在于它们解决的问题和实现的方式。
- 建造者模式更适用于创建复杂的对象,而工厂模式更适用于创建简单的对象。建造者模式通常需要一个指导者来控制构建过程, 通过设置不同的可选参数,“定制化”创建不同属性的对象。
- 工厂模式只需要一个工厂类即可。此外,建造者模式通常会在最终创建对象之前进行多个步骤的处理,而工厂模式直接创建对象。
4.3.5 适用的场景
结构复杂:对象有非常复杂的内部结构,有很多的属性
分离创建和使用:想把复杂对象的创建和使用分离,当创建一个对象需要很多的步骤,适合使用建造者模式,当创建一个对象的时候,只需要一个简单的方法就能够完成,适合使用工厂模式。
5.原型模式
5.1 问题场景
prototype 原型模式是用来创建重复的对象,同时能够保证有效的属性,这种类型的设计模式属于对象的创建型设计模式。它提供的是一种创建对象的最佳的方案,这种模式是实现了一个原型的接口,该接口用于创建当前对象的克隆。当创建一个对象的代价比较大的时候,能够采用这种模式,例如一个对象需要在一个高代价的数据库操作之后被创建,我们能够缓存该对象,在下一个请求的时候返回它的克隆,在需要的时候更新数据库,以此来减少数据库的调用。
5.2 场景假设
针对于原型模式的开发的场景,如同创建一个类,其中定义一定的属性,创建对象,每个对象都需要输入自己的属性值,相当于对于对象中的内容进行重新的输入,就好比写手写简历,大家的简历,格式都是一致的,拿到表格的时候,都需要进行信息的完善。造成的结果就是如果需要创建一个对象的代价比较大的时候,就比较麻烦了。
// 代码的验证
/**
* @author 法外狂徒张三
* 设计学生类对象
*/
public class Student {
private Integer id;
private String name;
private String address;
private String company;
/**
* 该构造器创建对象的时候,需要的属性分别是 名字,地址,公司
* 通过需要的属性创建需要的构造器,然后方便创建指定的对象
* @param name 名称
* @param address 地址
* @param company 公司
*/
public Student(String name, String address, String company) {
this.name = name;
this.address = address;
this.company = company;
}
public Student(Integer id, String name, String address, String company) {
this.id = id;
this.name = name;
this.address = address;
this.company = company;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", company='" + company + '\'' +
'}';
}
}
Demo1 验证类的实现
public class Demo1 {
public static void main(String[] args) {
Student student = new Student("战三", "中国河南", "中国电力局");
System.out.println(student);
Student student1 = new Student("战三1", "中国河南1", "中国电力局1");
System.out.println(student1);
}
}
总结:缺点是创建的对象都需要进行指定的信息填写,所以造成很多的不便之处,现在的信息是比较少,但是如果信息比较多的时候,我们将会十分的麻烦。
5.3 原型模式的实现
定义:原型模式,用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
总结:原型模式实际上就是从一个对象再创建另外一个可以定制的对象,而且不需要知道任何创建的细节。
5.3.1 实现的方式
// 创建Student对象
/**
* @author 法外狂徒张三
* 2023/3/17
*
* 通过实现接口,进行方法的重写,实现接口中的方法
*/
public class Student implements Cloneable{
private Integer id;
private String name;
private String address;
private String company;
/**
* 根据需要的地址名称创建指定的对象
* @param address 地址的名称
*/
public Student(String address) {
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
protected Student clone() {
Student student = null;
try {
student = (Student) super.clone();
} catch (CloneNotSupportedException e){
System.err.println("克隆出现异常的情况");
}
return student;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", company='" + company + '\'' +
'}';
}
}
// 验证操作
public class Demo2 {
@Test
public void test(){
Student student = new Student("商海");
student.setName("张三");
Student student1 = student.clone();
student1.setName("李四");
System.out.println(student);
System.out.println(student1);
}
}
// 运行结果
Student{id=null, name='张三', address='商海', company='null'}
Student{id=null, name='李四', address='商海', company='null'}
对比上面的操作的方式,对象增加了实现的接口Colneable ,需要进行重写方法 clone() 方法。
以至于,只要调用指定的方法就能够克隆对象。然后在通过指定的方法,实现对于自定义的对象约束。
一般在初始化的信息不发生改变的情况下,克隆是最好的解决的办法,这样既能够隐藏对象创建的细节,又能够对性能进行更大的提升。等于说不用初始化对象,而是动态地获取对象运行时的状态。
5.4 总结
5.4.1 概念
原型模式:是用来创建重复的对象,同时又能够保证性能,这种类型的设计模式属于创建型设计模式。它提供了一种创建对象的最佳的方式之一。
实现了一个原型的接口,该接口用于创建对象的克隆。当直接创建对象的代价比较大的时候,采用这种模式。例如:一个对象需要在一个高代价的数据库操作之后被创建,我们可以缓存该对象,在下一个请求时,返回它的克隆,在需要的时候更新数据库,以此来减少数据库的调用。
5.4.2 优点
- 性能高
- 逃避构造函数的约束
5.4.3 缺点
- 必须实现Cloneable接口
- 配备克隆方法需要对垒的功能进行通盘的考虑,这对于全新的类不是很难,但是对于已经有的类不一定很容易。特别当一个类引用不支持串行化的间接对象,或者引用含有循环的结构的时候。
5.4.4 使用场景
- 资源优化的场景
- 类初始化消耗非常多的资源,这个资源包括数据、硬件资源等,
- 性能和安全要求的场景
- 通过new产生一个对象需要非常繁琐的数据准备或者访问的权限,则可以使用原型的模式。
- 一个对象多个修改者的场景
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模型拷贝多个对象供调用者使用。
- 在实际的开发中,原型的项目很少单独的出现,一般都是和工厂模式一起出现,通过clone创建爱你一个对象,然后由工厂方法提供给调用者。