title: 从零玩转设计模式之建造者模式
date: 2022-12-08 18:15:30.898
updated: 2022-12-23 15:35:58.428
url: http://www.yby6.com/archives/jianzaozhemoshi
categories:
- 设计模式
tags:
- 设计模式
- 建造者模式
建造者模式是一种软件设计模式,它用于将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式通常用于创建复杂对象,它包含多个部分,每个部分可以有不同的组成方式。
一个类计算机类Computer包括以下变量
而其他3个是可选参数
第一种主要是使用及阅读不方便。当调用一个类的构造函数时,
首先要决定使用哪一个,里面参数又很多,参数的类型也不一样,
这样很容易搞混
在构建过程中对象的状态容易发生变化,造成错误。
因为那个类中的属性是分步设置的,所以就容易出错。
在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。
产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。
这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。
/**
* 产品 计算机
*
* @author yang shuai
* @date 2022/12/4
*/
public class Computer {
private final String cpu;// 必须
private final String ram;// 必须
private int usbCount;// 可选
private String keyboard;// 可选
private String display;// 可选
public Computer(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}
public void setUsbCount(int usbCount) {
this.usbCount = usbCount;
}
public void setKeyboard(String keyboard) {
this.keyboard = keyboard;
}
public void setDisplay(String display) {
this.display = display;
}
@Override
public String toString() {
return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", usbCount=" + usbCount + ", keyboard='" + keyboard + '\'' + ", display='" + display + '\'' + '}';
}
}
public abstract class ComputerBuilder {
public abstract void buildCount(int usbCount);
public abstract void buildKeyboard(String keyBoard);
public abstract void buildDisplay(String display);
public abstract Computer makeComputer();
}
public class HWComputerBuilder extends ComputerBuilder{
private Computer computer;
public HWComputerBuilder(String cpu, String ram) {
computer=new Computer(cpu,ram);
}
@Override
public void buildCount(int usbCount) {
computer.setUsbCount(usbCount);
}
@Override
public void buildKeyboard(String keyBoard) {
computer.setKeyboard(keyBoard);
}
@Override
public void buildDisplay(String display) {
computer.setDisplay(display);
}
@Override
public Computer makeComputer() {
return computer;
}
}
public class ComputerDirector {
private ComputerBuilder builder;
public void setBuilder(ComputerBuilder builder) {
this.builder = builder;
}
public Computer makeComputer(int useCount,String display,String keyBoard){
builder.buildCount(useCount);
builder.buildDisplay(display);
builder.buildKeyboard(keyBoard);
return builder.makeComputer();
}
}
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。即产品的组成部分是不变的,但每一部分是可以灵活选择的。
大白话:
封装性好,构建和表示分离。
扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
解决产生多余的Builder对象等
在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
示例:
/**
* 使用静态内部类构造数据
*
* @author yang shuai
* @date 2022/12/9
*/
public class Computer {
private final String cpu;//必须
private final String ram;//必须
private final int usbCount;//可选
private final String keyboard;//可选
private final String display;//可选
@Override
public String toString() {
return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", usbCount=" + usbCount + ", keyboard='" + keyboard + '\'' + ", display='" + display + '\'' + '}';
}
private Computer(Builder computerBuilder) {
this.cpu = computerBuilder.cpu;
this.ram = computerBuilder.ram;
this.usbCount = computerBuilder.usbCount;
this.keyboard = computerBuilder.keyboard;
this.display = computerBuilder.display;
}
public static class Builder {
private final String cpu;//必须
private final String ram;//必须
private int usbCount;//可选
private String keyboard;//可选
private String display;//可选
public Builder(String cup, String ram) {
this.cpu = cup;
this.ram = ram;
}
public Builder buildUsbCount(int usbCount) {
this.usbCount = usbCount;
return this;
}
public Builder buildKeyboard(String keyboard) {
this.keyboard = keyboard;
return this;
}
public Builder buildDisplay(String display) {
this.display = display;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
如果一个对象有非常复杂的内部结构(很多属性)
想把复杂对象的创建和使用分离
用来创建复杂的复合对象
MyBatis 中 SqlSessionFactoryBuiler 类用到了建造者模式。且在 MyBatis 中 SqlSessionFactory是由 SqlSessionFactoryBuilder 产生的
XMLConfigBuilder 负责 Configuration 各个组件的创建和装配,整个装配的流程化过程如下:
XMLConfigBuilder 负责创建复杂对象 Configuration,其实就是一个具体建造者角色。
SqlSessionFactoryBuilder 只不过是做了一层封装去构建 SqlSessionFactory 实例,这就是建造者模式简化构建的过程。
大家好,又见面了,我是你们的朋友全栈君。代价函数在监督学习的回归问题中,代价函数就是用于找到最优解的目的函数,反应了预测函数的准确性。代价函数的值越小,说明在回归问题的中,计算机程序对数据拟合的越好。也就是假设函数越正确。比如,对于这个假设函数(可以看成是求房价的假设函数):复制 代价函数是: 也就是预测值与真实值的差的平方和,再除以2m(2倍样本数量)。在假设函数中:θ0和θ1两个参数,不同的参数会有不同的假设函数 如下图所示: 在拟合数据的过程中,我们要不断的修改θ0和θ1这两个参数,来得到更好的参数,从而得到更准确的假设函数,也就就是预测函数。那么我们怎么来判断这些参数是否选取的更好,假设函数是否更准确呢?这时候就要用代价函数来反映这些问题。从costfunction中我们可以知道,代价函数的值越小那么我们的参数就选取的越好,假设函数预测的结果也就更准确。举个简单例子:复制这里是只有一个参数的假设函数: 我们把假设函数的参数设置成0.5那么他的图像是这样子:红色的是真实值。黑色直线是假设函数。 它的的假设函数是误差平方和,(毕竟有个平方在这里)为了减少极个别极端的数据,我们把误
介绍使用索引、临时表+文件排序实现groupby,以及单独介绍临时表的三篇文章中,多次以count(distinct)作为示例说明。 那还有必要单独为count(distinct)写一篇文章吗?此刻,想到一句台词:别问,问就是有必要。回到正题,MySQL使用MEMORY引擎临时表实现count(distinct)的去重功能时,玩出了新花样,所以,还是值得写一下的。背景说明到此为止,我们快快开始。本文内容基于MySQL5.7.35源码。1.概述如果count(distinct)不能使用索引去重,就需要使用临时表。临时表的存储引擎有三种选择:MEMORY、MyISAM、InnoDB。和使用MyISAM或InnoDB作为临时表的存储引擎处理逻辑有些不一样,如果MySQL决定使用MEMORY作为临时表的存储引擎,临时表会被创建,但只是作为辅助,表里不会写入任何数据。要说清楚为什么会有这种花样操作,需要从MEMORY引擎支持的两种索引结构说起。2.MEMORY支持的两种索引结构MEMORY引擎支持两种索引结构:HASH索引、B-TREE索引。HASH索引,顾名思义,索引的数据结构是哈希表。has
介绍虽然GPT-3已经发布了很长一段时间,因为它在编写类似人类的故事和诗歌方面的卓越能力而受到广泛关注,但我从来没有想到它附带的API能够为构建具有广泛应用程序的数据产品提供如此大的灵活性和方便性。在本文中,我试图探索一些与我在就业市场中看到的问题相关的用例,并试图理解构建基于语言的数据产品在未来可能只是围绕着“即时工程”。与此同时,本文并不试图解释GPT-3是如何工作的,也不试图解释它如何能够完成它正在做的事情。关于这些话题的更多细节已经在JayAlammar[1]和MaxWoolf[2]等文章中写得很详细。GPT-3论文本身可以在[3]中引用。在GPT-3的API中,'prompt'是提供给API的一个参数,以便它能够识别要解决的问题的上下文。根据提示的编写方式,返回的文本将尝试匹配相应的模式[4]。 下面是一个提示的例子,我们试图通过编程API来在银行部门的范围内提供答案。“Q:”和“A:”格式,连同问题文本和它的回答,提示模型,我们正在寻找的存在于银行领域(或至少,这是我如何理解它:))defcall_openapi(question): response=
现有的患者数据分析平台无法整合具有上下文,个性化和主题性的信息。为了使推荐系统对查询做出适当的响应或从患者数据中得出有意义的见解,推荐系统应考虑有关患者健康史的个人信息,包括但不限于其当前适用于患者的偏好,位置和生活选择他们。在这篇综述文件中,我们对这个领域的现有文献进行了评论,并讨论了为患者设计,构建和操作个人健康知识图谱(PHKG)带来的各种研究挑战。原文标题:PersonalHealthKnowledgeGraphsforPatients原文:Existingpatientdataanalyticsplatformsfailtoincorporateinformationthathascontext,ispersonal,andtopicaltopatients.Forarecommendationsystemtogiveasuitableresponsetoaqueryortoderivemeaningfulinsightsfrompatientdata,itshouldconsiderpersonalinformationaboutthepatient'shealt
一、部署IPsec关键点: 1)先定义ACL和保证需要加密的数据IP层可达; 2)要定义IKEProposal、IKEPeer、IPSecProposal和IPSecPolicy;3)注意上述配置中只有IPSecPolicy配置需引用IPSecProposal和IKEPeer;4)将定义好的IPSecPolicy绑定到指定的出接口。二、实验Toplogy三、实验步骤:1、省略R1、R2、R3的接口IP配置2、R1:1.配置需要加密传送的ACL[R1]acl num3000[R1-acl-adv-3000]rule permit ipsource1.1.1.10.0.0.0destination3.3.3.30.0.0.02.IKE策略配置[R1]ikeproposal 10 //创建IKE提议,并进入IKE视图[R1-ike-proposal-10]encryption-algorithm3des-cbc //使用3DES的加密算法[R1-ike-proposal-10]authentication-method pre-sh
作者:bravoban(Java架构沉思录做了部分修改) 原文:http://tech.lede.com/2017/03/08/rd/server/Redisson/复制针对项目中使用的分布式锁进行简单的示例配置以及源码解析,并列举源码中使用到的一些基础知识点,但是没有对redisson中使用到的netty知识进行解析。 本篇主要是对以下几个方面进行了探索Maven配置RedissonLock简单示例源码中使用到的Redis命令源码中使用到的lua脚本语义源码分析Maven配置<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>2.2.12</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId&
原文出自:http://cmsblogs.com在上篇博客【死磕Spring】-----加载bean之分析各scope的bean创建中有一个核心方法没有讲到createBean(),该方法的如下:protectedabstractObjectcreateBean(StringbeanName,RootBeanDefinitionmbd,@NullableObject[]args)throwsBeanCreationException;复制该方法定义在AbstractBeanFactory中。其含义是根据给定的BeanDefinition和args实例化一个bean对象,如果该BeanDefinition存在父类,则该BeanDefinition已经合并了父类的属性。所有Bean实例的创建都会委托给该方法实现。方法接受三个参数:beanName:bean的名字mbd:已经合并了父类属性的(如果有的话)BeanDefinitionargs:用于构造函数或者工厂方法创建bean实例对象的参数该抽象方法的默认实现是在类AbstractAutowireCapableBeanFactory中实现,
在此提醒大家,如果是基于KSDK开发的软件,跟单独基于MQX的在配置上有些不同,飞思卡尔对kinetisMCU的SDK从1.1.0以后,已经包含MQXRTOS,即我们经常提到的MQX+SDK,源码结构上跟单独的MQX有些变动,开发时候,要注意。如果你是新学习基于kinetisMCU的开发,建议安装KSDK,目前最新版本是1.2.0,这一版已经支持kv系列。在最新版的单独的MQXRTOS中还是没有支持kv系列的BSP包,如果是使用kv系列,需要自己移植BSP,可借助飞思卡尔的BSP克隆工具,非常方便,针对kv4x系列有一个单独的KSDK安装文件,KSDK1.1.0_KV4xF_1.0.0也是支持MQX的。 用户ISR安装用户自己开发的中断程序要能够得到正确调用,必须在系统初始化时候调用中断安装函数,_int_install_isr,将用户ISR安装到中断向量表,中断安装函数的参数有三个,中断向量号,中断服务例程入口地址,中断服务例程的参数。当需要响应一个中断时候,会通过_int_install_isr,转向执行用户的ISR。该函数位于内核源码包内的kernel文件夹下的int.c文件中,
Nexus是一个基于maven的仓库管理的社区项目。主要的使用场景就是可以在局域网搭建一个maven私服,用来部署第三方公共构件或者作为远程仓库在该局域网的一个代理。通过Docker启动$dockerrun-d\ --namenexus\ -p8081:8081\ -vnexus-data:/nexus-data\ sonatype/nexus3复制AndroidStudio配置项目buid.gradleallprojects{ repositories{ jcenter() // mavenLocal() } }复制appallprojects{ repositories{ maven{ url"https://nexus.khs1994.com/repository/com.khs1994.khs1994lib/" } } }复制libuploadArchives{ repositories.mavenDeployer(){ repository(url:"https://nexus.khs1994.com/repository/com.khs1994
DDoS攻击DistributedDenialofService(DDoS),即分布式拒绝服务攻击,是指攻击者通过网络远程控制大量僵尸主机向一个或多个目标发送大量攻击请求,堵塞目标服务器的网络带宽或耗尽目标服务器的系统资源,导致其无法响应正常的服务请求。 网络层DDoS攻击网络层DDoS攻击主要是指攻击者利用大流量攻击拥塞目标服务器的网络带宽,消耗服务器系统层资源,导致目标服务器无法正常响应客户访问的攻击方式。常见攻击类型包括SYNFlood、ACKFlood、UDPFlood、ICMPFlood以及DNS/NTP/SSDP/memcached反射型攻击。 CC攻击CC攻击主要是指通过恶意占用目标服务器应用层资源,消耗处理性能,导致其无法正常提供服务的攻击方式。常见的攻击类型包括基于HTTP/HTTPS的GET/POSTFlood、四层CC以及ConnectionFlood等攻击方式。 清洗当目标IP的公网网络流量超过设定的防护阈值时,腾讯云DDoS防护系统将自动对该IP的公网入向流量进行清洗。通过BGP路由协议将流量从原始网络路径中重定向到腾讯云DDoS清洗设备上,通过清洗设备对该I
sysmon里采集到的数据: +System -Provider [Name]Microsoft-Windows-Sysmon [Guid]{5770385F-C22A-43E0-BF4C-06F5698FFBD9} EventID3 Version5 Level4 Task3 Opcode0 Keywords0x8000000000000000 -TimeCreated [SystemTime]2022-10-09T03:46:19.534422100Z EventRecordID311410 Correlation -Execution [ProcessID]4044 [ThreadID]2624 ChannelMicrosoft-Windows-Sysmon/Operational ComputerWIN-0BIKIQLCCRQ -Security [UserID]S-1-5-18 -EventData RuleName- UtcTime2022-10-0903:46:06.642 ProcessGuid{2307292D-39CD-6
这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/CST2020-2 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2020-2/homework/11757 这个作业的目标 回顾数据类型和表达式,巩固文件的使用,学会用文件来解决问题 学号 20208999 一、本周教学内容&目标、 第6章回顾数据类型和表达式,第12章文件。 二、本周作业(总分:50分) 2.1题目:给定一个十进制正整数N,写下从1开始,到N的所有整数,然后数一下其中出现的所有“1”的个数。 例如: N=2,写下1,2。这样只出现了1个”1“。 N=12,我们会写下1,2,3,4,5,6,7,8,9,10,11,12。这样,1的个数是5。 问题是: 1.写出一个函数f(N),返回1到N之间出现的”1“的个数,比如f(12)=5; 2.满足条件”f(N)=N“的最大的N是多少? 要求: 1.贴出代码图片,写出解题思路,列出测试数据(5分) 解题思路:一开始就想着直接暴力解法,遍历1~
国际化支持 1.安装依赖 执行以下命令,安装i18n依赖。 yarnaddvue-i18n复制 $yarnaddvue-i18n yarnaddv1.9.4 warningpackage-lock.jsonfound.YourprojectcontainslockfilesgeneratedbytoolsotherthanYarn.Itisadvisednottomixpackagemanagersinordertoavoidresolutioninconsistenciescausedbyunsynchronizedlockfiles.Toclearthiswarning,removepackage-lock.json. [1/5]Validatingpackage.json... [2/5]Resolvingpackages... [3/5]Fetchingpackages... infofsevents@1.2.4:Theplatform"win32"isincompatiblewiththismodule. info"fsevents@1.2.4"isanoptional
Azure云服务在中国市场风生水起,越来越多的用户选择Azure作为平台将业务转向云端。随着移动互联网在中国的蓬勃发展,手机应用的体验深入人们的生活及工作。用户管控云服务也不应该只局限于电脑前,而是可以随时随地的在手机端监控和管理。云服务的任何问题也应该在手机端实时通知用户,从而得到及时处理。 Azure云助手(AzureCloudAssistant,aka,ACA)因此应运而生。ACA是MicrosoftAzure的官方唯一手机管理工具,可为用户提供24小时不间断的云业务监控和管理服务,让用户感受上云/用云/管云,从未如此简单!ACA由微软云计算和企业事业部设计开发,目前已经登陆iOSAppStore以及安卓的各大应用商店(腾讯,360,百度,小米,三星,华为等)。 扫描二维码快速安装,或点击这里安装 (任何问题请联系Azureme@microsoft.com) 主要功能: 实时查询:实时查询Azure云服务的用量和账单,还可以将重点服务固定在首页“我的监控”页面,方便快速查看。 随时管控:随时随地对云服务管理和配置(例如,重启、更改虚拟机)。 多个账户:随心切换多账户
只有1行,为2个正整数,用一个空格隔开: kN (k、N的含义与上述的问题描述一致,且3≤k≤15,10≤N≤1000)。 计算结果,是一个正整数(在所有的测试数据中,结果均不超过2.1*10^9)。(整数前不要有空格和其他符号)。 #include<stdio.h> intn2[1010];longlongl1=1;longlongn,k;longlongsm(longlongi,longlongk){longlongs=1;intj;for(j=1;j<=i;j++){s*=k;}returns;}intmain(){inti;scanf("%lld%lld",&k,&n);while(n>0){n2[l1++]=n%2;n/=2;}l1--;longlongs=0;for(i=1;i<=l1;i++){if(n2[i]){s+=sm(i-1,k);}}printf("%lld",s);return0;}
自己尝试敲后缀数组,发现难看(tiao)的不行,于是抄了板子 考虑建出hei以后转化出的问题: 对于一个数组中权值大于等于k的连续部分,求取两个数的方案数和两数积的最大值 (好气啊,可以有负数) 把询问倒序以后相当于连续部分之间会动态加元素,使他们连起来 维护一段极大连续段的最大值、最小值、长度,保存在左右两端——wtf我也不知道这算什么做法 然后瞎**乱搞一下,就能每次合并O(1)维护出来了(似乎没比并查集好多少) 1#include<bits/stdc++.h> 2#defineN300001 3#defineMIN-9223372036854775807 4#definecalc(x)(x)*((x)-1)/2 5#definelllonglong 6usingnamespacestd; 7lln,ans,ans2; 8llc[N],mi[N],ma[N],len[N],w[N]; 9llsa[N],Rank[N],height[N]; 10llwa[N],wb[N],wv[N],wd[N]; 11llout1[N],out2[N]; 12structnode 13
一、前言 不好的习惯:1、每一次用到正则都是上网copy一份,也没有去学习思考,看看都是什么意思; 2、一个项目里不同的地方用到了相同的校验,一直在重复的copy代码,并没有统一起来,万一哪天要修改规则,若是多人开发,每个人的正则校验不尽相同,改起来就很麻烦。 先记录一下,后续慢慢学习,最后自己能看懂并会写常用的正则。 二、正则基本知识点 1、横向模糊匹配{}: 一个正则可以匹配的字符串的长度不是固定的,使用量词可以达到这种目的。 量词:比如{m,n}:表示连续出现最少m次,最多n次;跟在一个字符的后面就表示对该字符的限定。 比如邮箱的校验:/^\w+@[a-z0-9]+\.[a-z]{2,4}$/,写在了[a-z]后面,表示可以有2到4位的字母; 比如手机号的校验: /^1[3456789]\d{9}$/,跟在了\d后面,表示需要出现9个数字 {m,n}:表示连续出现最少m次,最多n次 {m,}:表示至少出现m次 {m}:表示出现m次 ? :等价于{0,1}表示出现或不出现 +:等
十一.统计类函数使用 如果我们想知道总用户数怎么办? 查询谁是数据表里的首富怎么办? 如果我们想知道用户的平均金额怎么办? 如果我们想知道所有用户的总金额怎么办? 统计类函数最常用的我们有四个: 函数说明 sum求和 count统计总数 max最大值 min最小值 avg平均值 注:当然你知道其他的mysql函数也可以使用。不过,在实际工作中,大公司的很多大中型项上很少使用,他们都有专门的计数服务器。因为,mysql的计算量本身很大,为了减少压力通常我们将实际的计算任务交给业务服务器或其他服务器来完成 十二分组groupby 我们那金额表里面的省份进行分组数据,分组数据后你会发现有相同的省份会去掉,即一个省份为一个组. 语法:select*from表groupby字段 eg:select*frommoneygroupbyprovince; ps:按照地区进行分组 mysql>select*frommoneygroupbyprovince; +----+-----------+---------+-----------+-----+-----+ &n
1.Object.defineProperty Object.defineProperty()方法会直接在一个对象上定义个新属性,或者修改一个对象的现有属性,并返回此对象。该方法允许精确地添加或修改对象的属性。 Object.defineProperty(obj,prop,descriptor) 复制 obj:即为作用的对象 prop:即为对象上的某个属性 descriptor:属性描述符,是个对象 //举例 letobj={ name:'fct' } //为obj对象增加属性age,并设置具体约束 Object.defineProperty(obj,'age',{ //.... }) 复制 1.1属性描述符 属性描述符有两种主要形式:数据描述符和存取描述符。 数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。 存取描述符是由getter函数和setter函数所描述的属性。 一个描述符只能是这两者其中之一;不能同时是两者。 //不能同时是两者。只能以下 Object.defineProperty(obj,'age',{ enumerable:false, confi
内容已过期,最新内容请查看: https://www.cnblogs.com/yitter/p/14610169.html 比雪花算法更好用的ID生成算法(单机或分布式唯一ID) ?算法介绍 ❄一个全新的雪花漂移算法,生成的ID更短、速度更快。 ❄核心在于缩短ID长度的同时,具有极高瞬时并发处理量(保守值50W/0.1s)。 ❄原生支持C#/Java/Go/Rust/C等语言,并由Rust提供PHP、Python、Node.js、Ruby等语言多线程安全调用库(FFI)。如果你的应用有语言开发,基于本算法提供的逻辑实现,集成会更简单,逻辑会更一致。 ❄支持k8s等容器化部署,自动注册WorkerId。 ❄可在单机或分布式环境中生成唯一ID。 ?技术支持 开源地址1:https://gitee.com/yitter/idgenerator 开源地址2:https://github.com/yitter/idgenerator QQ群:646049993 需求来源 ?作为架构设计的你,想要解决数据库主键唯一的问题,特别是在分布式系统多数据库的时候。 ?你希望这个主键是用最少的存储空间,索引