复用:一个软件的组成部分可以在同一个项目的不同地方甚至在不同的项目重复使用。
面向对象设计复用的目标:实现支持可维护性的复用。(抽象、继承、封装、多态)
重构:在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量、性能、使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码,让代码更容易被他人理解、保证代码的可靠性。
根据目的(模式是用来做什么的)可以分为创建型(Creational)、结构型(Structural)和行为型(Behavioral)三种
根据范围(模式主要是用于类之间的关系还是处理对象之间的关系)可以分为类模式和对象模式两种
例子:根据计算机组件组装不同的计算机。
用这个例子来理解一下创建者模式:首先这个模式做的事情是这样的,现在有一堆计算机零件,比如说一块硬盘它可以放在笔记本电脑上也可以放在台式机上,那么建造者模式就是把不同电脑的构建和表示分离,提供一个计算机产品类,里面包含了计算机的零件,之后提供一张“图纸”这张图纸就是一个抽象建造者接口,这个接口提供了创建的方法以及返回复杂对象的方法,具体的建造者会实现这个接口,用这张“图纸”来创造不同类型的计算机。
具体角色:
注意点:
抽象建造者里要去new一个具体产品。
protected Computer computer = new Computer();
抽象建造者里需要定义一个返回复杂产品的方法
public Computer getComputer(){
return computer;
}
具体建造者继承自抽象建造者,实现里面的所有建造方法!
public class DeskTopBuilder extends ComputerBuilder
指挥者类是真正干活的类
public class ComputerWaiter {
private ComputerBuilder cb;
public void setCb(ComputerBuilder cb){
this.cb=cb;
}
public Computer construct(){
cb.buildCPU();
cb.buildHardDisk();
cb.buildMainFrame();
cb.buildMemory();
return cb.getComputer();
}
}
这个类需要拥有一个抽象建造者的对象,利用这个对象调用其建造的方法来完整一个具体的产品并调用其方法把这个产品返回!
总结:
核心理解
建造者模式的核心在于抽象建造者类,这个类要做的事情是定义方法:首先这个类是用来建造一个实例对象的,所以一定要new一个新的产品对象作为其属性成员,然后定义建造的接口方法,根据具体需要被建造的实例的setter方法提供不同的多个建造方法接口,最后需要一个方法返回最终建造完成的对象。
这个抽象建造方法就是一张建造的图纸,后面实现这个接口的类是具体的建造图纸,把具体的建造图纸用set注入的方式给指挥者类(相当于工人)让指挥者类干活,最后根据具体图纸完成一个实例产品!
具体角色:
步骤:
实现一个接口:Cloneable
重写一个方法:clone
pubilc Object clone()
object = super.clone() ;
return object;
核心理解
原型模式只做了一件事情,就是克隆一份一模一样的自己并返回。
注意点:
package com.a007;
public class StuNo
{
//静态私有成员变量
private static StuNo instance=null;
private String no;
//私有构造方法
private StuNo()
{
}
//静态公有工厂方法,返回唯一实例
public static StuNo getInstance()
{
if(instance==null)
{
System.out.println("新学号");
instance=new StuNo();
instance.setStuNo("20194074");
}
else
{
System.out.println("学号重复,获得旧学号");
}
return instance;
}
private void setStuNo(String no)
{
this.no=no;
}
public String getStuNo()
{
return this.no;
}
}
核心理解
单例模式做的事情是保证一个类有且只有一个实例对象!
用途:将一个类的接口转换成客户希望的另一个类的接口。
例子:电脑网线USB转接器
角色:
电脑(客户端)、网线、转接器、目标接口NetToUsb
分类:
类图:(双向适配)

核心理解
适配器模式做的事情是这样的:
有两个不相干的类,但是它们想组合到一起使用,那么就通过一个适配器把二者适配在一起使用。
比如说:电脑有一个USB接口,而网线的接头不是USB的,可是电脑想上网,那么就需要一个接口转接的适配器来完成这个工作,这时候会出现三个类。



图片来自bilibili遇见狂神说
核心理解
桥接模式做了这样一件事情:
就像图中所示:如果想要一个联想的台式电脑,那么就需要两层继承来拿到这个对象(类),第一这是低效率的,第二这是一种静态的定死的方式,扩展性很差。桥接模式的思想是把抽象化和实现化进行解耦分离,比如说无论有多少个品牌,抽象来看它们都只是品牌,无论有多少种电脑,它们都只是电脑。这样的话可以抽象出两个维度,一个是类型、另一个是品牌。具体的实现就是自由组合:XX品牌的XX种类电脑。
优化:本来如果要这九种电脑需要3*3=9个类,现在需要这些电脑只需要3+3=6个类,如果数量级更大,桥接模式的好处可想而知,可以大大减少子类的个数!
根据依赖倒转原则,实现要依赖抽象,所以首先会有一个抽象的电脑类,这个抽象类的子类是各种类型的电脑,其次需要一个电脑的品牌接口,实现这个接口的类是各种品牌!
这个抽象电脑类和品牌接口类是组合的关系,抽象电脑类通过Setter方法注入一个具体的电脑品牌对象,然后用其方法结合自身的电脑种类获得这个品牌的各种类型的电脑!
补充:【抽象类和接口的区别】
含有abstract修饰符的class即为抽象类,abstract 类不能创建实例对象。含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
下面比较一下两者的语法区别:
抽象类可以有构造方法,接口中不能有构造方法。
抽象类中可以有普通成员变量,接口中没有普通成员变量
抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然
eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
定义:动态地给一个对象增加一些额外的职责。
角色:
模式分析:
具体构件类和抽象构件类都实现了抽象构件接口,模式的关键在于抽象装饰类,这个类实现了抽象构件接口并且组合了抽象构件,在其构造函数中设置参数注入具体构件对象,在其装饰方法中调用这个注入的构件类已有的方法,再通过具体装饰类的继承,添加其他方法和功能。

核心理解
装饰模式做的事情是动态修改被装饰者的一些属性方法等等。
根据依赖倒转原则,待装饰的类和装饰者类都要实现自同一个抽象构件接口,在装饰者类的构造方法里要注入一个待装饰者对象,装饰者类和抽象构件接口是组合关系和接口实现关系,在装饰者类中提供一个可扩展的方法供子类重写。
具体的装饰者类继承抽象装饰者类,重写其扩展方法完成对待装饰对象的装饰!
定义:外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统的一组接口提供 了一个一致的界面。
实例:一个电源总开关可以控制四盏灯、一个风扇、一台空调和一个电视机的启动和关闭。
类图:

核心理解
外观模式做的事情是这样的:
比如说你现在想把家里的灯关了、把空调关了、把电视机也关了。正常的过程是你要一个个去把它们关闭,但是如果给你一个统一的关闭按钮,只要你按这一个按钮,这三种电器就会同时关闭,这样的一个按钮的实现,就是外观模式的核心!
使用简单的关联关系,实现对多个对象的方法的同时调用,统一分配!
定义:
给某个对象提供一个代理,并由代理对象控制对原对象的引用。
角色:

核心理解
代理模式的关键在于:
首先根据依赖倒转原则:具体主题类和代理主题类都要实现自同一个抽象主题角色。
代理主题类关联真实主题类,代替真实主题针对不同的客户做出不同的处理!
定义:避免请求的发送者和接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,沿着这条链传递请求,直到有对象处理它为止。
角色:
模式分析:
关键在于抽象处理者类的设计:很多对象由每一个对象对其下家的引用而连接在一起。
抽象处理者典型代码:
//审批者类:抽象处理者
abstract class Approver {
protected Approver successor; //定义后继对象
protected String name; //审批者姓名
public Approver(String name) {
this.name = name;
}
//设置后继者
public void setSuccessor(Approver successor) {
this.successor = successor;
}
//抽象请求处理方法
public abstract void processRequest(PurchaseRequest request);
}
具体处理者典型代码:
//董事长类:具体处理者
class ViceManager extends Approver {
public ViceManager(String name) {
super(name);
}
//具体请求处理方法
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 100000) {
System.out.println("副总经理" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
}
else {
this.successor.processRequest(request); //转发请求
}
}
}
客户端调用典型代码:轮流设置下家
position1.setSuccessor(position2);
position2.setSuccessor(position3);
position3.setSuccessor(position4);
position4.setSuccessor(meeting);
package com.c015;
public class Client {
public static void main(String[] args) {
Approver position1,position2,position3,position4,meeting; // 多个处理者
position1 = new Director("甲");
position2 = new PartManager("乙");
position3 = new ViceManager("丙");
position4 = new Manager("丁");
meeting = new Congress("职工大会");
//创建职责链
position1.setSuccessor(position2);
position2.setSuccessor(position3);
position3.setSuccessor(position4);
position4.setSuccessor(meeting);
//创建采购单
PurchaseRequest pr1 = new PurchaseRequest(5000,10001,"XXX");
position1.processRequest(pr1);
PurchaseRequest pr2 = new PurchaseRequest(45000,10002,"XXX");
position1.processRequest(pr2);
PurchaseRequest pr3 = new PurchaseRequest(77000,10003,"XXX");
position1.processRequest(pr3);
PurchaseRequest pr4 = new PurchaseRequest(150000,10004,"XXX");
position1.processRequest(pr4);
PurchaseRequest pr5 = new PurchaseRequest(800000,10005,"XXX");
position1.processRequest(pr5);
}
}
核心理解
职责链模式关键在于设置职责的下家!
抽象处理者类要有一个自身的对象作为成员属性变量,并通过一个set方法完成赋值,之后要提供一个具体处理的方法接口供子类重写!
后续的子类重写具体的处理办法,如果处理不了,再次调用父类的处理方法直接把请求交给下家来完成!
定义:
将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化。
本质上是对命令进行封装,将发出命令的责任和执行命令的责任分隔开。
角色:
关键代码:
//接收者:真正执行命令的对象
public class Light {
public void open(){
System.out.println("打开电灯!");
}
}
public interface Command {
public void execute();
}
// 这是一个命令,所以需要实现Command接口
public class LightOnCommand implements Command {
Light light;
// 构造器传入某个电灯,以便让这个命令控制,然后记录在实例变量中
public LightOnCommand(Light light) {
this.light = light;
}
// 这个execute方法调用接收对象的on方法
public void execute() {
light.on();
}
}
public class SimpleRemoteControl {
// 有一个插槽持有命令,而这个命令控制着一个装置
Command slot;
public SimpleRemoteControl() {}
// 这个方法用来设置插槽控制的命令
public void setCommand(Command command) {
slot = command;
}
// 当按下按钮时,这个方法就会被调用,使得当前命令衔接插槽,并调用它的execute方法
public void buttonWasPressed() {
slot.execute();
}
}
客户端使用
public class RemoteControlTest {
public static void main(String[] args) {
// 遥控器就是调用者,会传入一个命令对象,可以用来发出请求
SimpleRemoteControl remote = new SimpleRemoteControl();
// 现在创建一个电灯对象,此对象也就是请求的接收者
Light light = new Light();
// 这里创建一个命令,然后将接收者传给它
LightOnCommand lightOn = new LightOnCommand(light);
// 把命令传给调用者
remote.setCommand(lightOn);
// 模拟按下按钮
remote.buttonWasPressed();
}
}
核心理解
命令模式主要完成的事情是把命令的具体实施和命令的发出解耦。
有一个具体干活的类(命令接收者类),这个类里有所有执行具体命令的方法。
有一个抽象的命令类,这个类定义了一个执行的方法接口,然后它的子类(这些子类的个数和具体命令的个数是一致的,比如说那个具体干活的类需要做两件事,一个是打开电脑,一个是关闭电脑,那么就会有两个不同的子类来继承这个抽象的命令类!)继承这个类并重写它的执行命令的方法,这里有个点需要注意:这些子类需要关联那个命令接收者类,用那个类的方法来重写执行方法!
定义:
定义了遍历和访问元素的接口,一般声明如下方法:用于获取第一个元素的first(),用于访问下一个元素的next(),用于判断是否还有下一个元素的hasNext(),用于获取当前元素的currentItem()。
定义:
定义对象之间的一种一对多的依赖关系,使得每当一个对象的状态发生变化时,其相关的依赖对象都可以得到通知并被自动更新。
模式主要用于多个不同的对象对一个对象的某个方法会做出不同的反应!
比如猫叫之后狗会叫老鼠会逃跑,这时候猫就是被观察者,老鼠和狗都是观察者。
角色:
核心理解
观察者模式做的事情是这样的:
有这么一个场景,比如说一个对象的某个变化会造成其他类的不同的反应,比如说股票的涨跌和股民的状态就是一种动态的关联变化,观察者模式就是来描述这样的一个场景的!
具体是这样完成的:
根据依赖倒转原则,首先需要一个抽象的被观察的类,这个类拥有的成员属性变量是和它有关系的那些观察者对象,一般是有多个对象,如果这个属性是一个集合,那么需要定义两个接口方法,一个增加一个删除,最后还需要一个描述自身状态的方法。
具体的被观察者继承自抽象的被观察类, 这个类重写它的状态变化方法!注意这个方法需要遍历所有观察者对象的response方法
观察者同样也需要进行抽象,需要一个观察者接口类,这个类只有一个方法就是response()
具体的观察者实现这个接口,重写response方法!
客户端在调用时,需要把观察者添加到被观察者里,然后调用被观察者的状态变化方法,就会看到它所有的观察者对这个状态做出的不同的反应!
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图