目录介绍
1.访问者模式介绍 2.访问者模式定义 3.访问者模式UML图 4.访问者模式简单案例 5.访问者模式之Android源码分析 5.1 注解简单介绍 5.2 注解与访问者模式关系 5.3 注解与性能的关系 6.访问者模式之实践 6.1 介绍 6.2 编译期注解之ButterKnife 6.3 编译期注解之Dagger2 6.4 自己写个简单支持View的ID注入的工具 6.4.0 基本逻辑思路 7.注解之ButterKnife源码分析 7.0 简单工作流程 7.1 首先看看Bind注解 7.2 看看支持的类型 7.3 编译时注解之ButterKnifeProcessor 7.4 接下来看看findAndParseTargets(env)代码 7.5 然后看看parseBind方法 7.6 看看parseBind中的parseBindMany方法 7.7 回到bindingClass.brewJava()方法中 7.8 接下来看注解过程,bind方法 7.9 看注解过程中bind中的findViewBinderForClass 方法
好消息
博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
链接地址:https://github.com/yangchong211/YCBlogs
如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!
0.本人写的综合案例**
案例
说明及截图
模块:新闻,音乐,视频,图片,唐诗宋词,快递,天气,记事本,阅读器等等
接口:七牛,阿里云,天行,干货集中营,极速数据,追书神器等等
持续更新目录说明:http://www.jianshu.com/p/53017c3fc75d
1.访问者模式介绍
访问者模式,是一种将数据操作和数据结构分离的设计模式. 大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是真地需要它了.
2.访问者模式定义
定义:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作. 优点: 1.各角色职责分离,符合单一职责的原则 2.具有优秀的扩展性 3.使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化 4.灵活性 缺点: 1.具体元素对访问者公布细节,违反了迪米特原则 2.具体元素变更时导致修改成本变大 3.违反了依赖导致原则,为了达到”区别对待”而依赖了具体类,没有依赖抽象. 使用场景: 1.对象结构比较稳定,但经常需要在此对象结构上定义新的操作. 2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作
3.访问者模式UML图
Visitor:接口或者抽象类,它定义了对每一个元素的访问行为,它的参数就是可以访问的元素 ConcreteVisitor:具体访问者,对每一个元素类访问的具体行为 Element:元素接口或者抽象类,定义了一个accept方法,每一个月uansu都要可以被访问者访问 ElementA:具体元素类,它提供了接受访问的具体方法实现 ObjectStructure:对象结构,内部管理元素集合,并且可以迭代这些元素供访问者访问
4.访问者模式简单案例
5.访问者模式之Android源码分析
5.1 注解简单介绍 注解分类:运行时注解,编译期注解 通俗的分析如下所示: 1、标记一些信息,这么说可能太抽象,那么我说,你见过@Override、@SuppressWarnings等,这类注解就是用于标识,可以用作一些检验 2、运行时动态处理,这个大家见得应该最多,在运行时拿到类的Class对象,然后遍历其方法、变量,判断有无注解声明,然后做一些事情。类似上述三篇博文中的做法。 3、编译时动态处理,,一般这类注解会在编译的时候,根据注解标识,动态生成一些类或者生成一些xml都可以,在运行时期,这类注解是没有的会依靠动态生成的类做一些操作,因为没有反射,效率和直接调用方法没什么区别 运行时注解 编译期注解,编译注解的核心原理依赖APT,比如ButterKnife,Dagger,Retrofit等都是基于APT的 编译时,Annotation解析的原理: 原理是在某些代码元素上(如类型、函数、字段等)添加注解,在编译时编译器会检查AbstractProcessor的子类,并且调用该类型的process函数,然后将添加了注解的所有元素都传递到process函数中,使得开发人员可以在编译器进行相应的处理,例如,根据注解生成新的Java类,这也就是EventBus,Retrofit,Dragger等开源库的基本原理。
5.2 注解与访问者模式关系
5.3 注解与性能的关系 只要解析出来是注解和反射,必然的一个问题就是:这样会不会影响性能呀?会有性能的损耗
6.访问者模式之实践
6.1 介绍 实际开发中该模式用的少,具有实战意义的是编译期注解,就是APT示例。 6.2 编译期注解之ButterKnife ButterKnife简单介绍 编译期注解的库【基于编译时注解,然后通过APT生成辅助类,在运行时通过bind函数调用那些生成的辅助类来完成功能】 针对View,资源ID等进行注解 6.3 编译期注解之Dagger2 Dagger2简单介绍 编译期注解的库 针对对象进行注解 6.4 自己写个简单案例 6.4.0 基本逻辑思路 通过ViewInject注解标识一些View成员变量; 通过ViewInjecyProcessor捕获添加了ViewInject注解的元素,并且按照宿主类进行分类; 为每个含有ViewInject注解的宿主类生成一个InjectAdapter辅助类,并且在它的inject函数中生成初始化View的代码; 在SimpleDagger的inject函数中构建生成的辅助类,此时内部会它这个InjectAdapter辅助类的inject函数,这个函数中又会初始化宿主类中的View成员变量,至此,View就已经被初始化了。
7.注解之ButterKnife源码分析
7.0 简单工作流程 开始它会扫描Java代码中所有的ButterKnife注解@Bind、@OnClick、@OnItemClicked等。 当它发现一个类中含有任何一个注解时,ButterKnifeProcessor会帮你生成一个Java类,名字类似$$ViewBinder,这个新生成的类实现了ViewBinder接口。 这个ViewBinder类中包含了所有对应的代码,比如@Bind注解对应findViewById(), @OnClick对应了view.setOnClickListener()等等。 最后当Activity启动ButterKnife.bind(this)执行时,ButterKnife会去加载对应的ViewBinder类调用它们的bind()方法。 7.1 首先看看Bind注解 @Retention保留时间,可选值SOURCE(源码时),CLASS(编译时),RUNTIME(运行时),默认为CLASS,值为SOURCE大都为MarkAnnotation,这类Annotation大都用来校验,比如Override,Deprecated,SuppressWarnings @Target可以用来修饰哪些程序元素,如TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER等,未标注则表示可修饰所有
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.CLASS;
//说明就是编译时动态处理的 这个值是一个枚举:有三个:SOURCE、RUNTIME、CLASS
@Retention(CLASS)
//标明这个注解能标识哪些东西,比如类、变量、方法、甚至是注解本身(元注解)等
@Target(FIELD)
public @interface Bind {
/** View ID to which the field will be bound. */
int[] value();
}
7.2 看看支持的类型
7.3 编译时注解之ButterKnifeProcessor Annotation processing是在编译阶段执行的,它的原理就是读入Java源代码,解析注解,然后生成新的Java代码。新生成的Java代码最后被编译成Java字节码,注解解析器(Annotation Processor)不能改变读入的Java 类,比如不能加入或删除Java方法。 这个是编译过程中很重要的一部分,对于butterKnife所有的注解,都是在编译时进行注解。其中ButterKnifeProcessor这个类是继承AbstractProcessor,并重写 process方法 来看看Process方法中的源代码
@Override
public boolean process(Set elements, RoundEnvironment env) {
//获取所有注释的元素并且解析
Map targetClassMap = findAndParseTargets(env);
//循环遍历,获取到注解中的键值
for (Map.Entry entry : targetClassMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BindingClass bindingClass = entry.getValue();
try {
//写进文件,生成辅助类
JavaFileObject jfo = filer.createSourceFile(bindingClass.getFqcn(), typeElement);
Writer writer = jfo.openWriter();
writer.write(bindingClass.brewJava());
writer.flush();
writer.close();
} catch (IOException e) {
error(typeElement, "Unable to write view binder for type %s: %s", typeElement,
e.getMessage());
}
}
return true;
}
7.4 接下来看看findAndParseTargets(env)代码 遍历,然后比较并且解析
private Map findAndParseTargets(RoundEnvironment env) {
//创建一个map集合,用来存储所有注释的元素的键值对
Map targetClassMap = new LinkedHashMap();
//创建删除删除目标名称的set集合
Set erasedTargetNames = new LinkedHashSet();
//遍历
// Process each @Bind element.
for (Element element : env.getElementsAnnotatedWith(Bind.class)) {
try {
//解析
parseBind(element, targetClassMap, erasedTargetNames);
} catch (Exception e) {
logParsingError(element, Bind.class, e);
}
}
}
7.5 然后看看parseBind方法 重点了解一下几个方法
isInaccessibleViaGeneratedCode 验证方法修饰符不能为private和static 验证包含类型不能为非Class 验证包含类的可见性并不是private
isBindingInWrongPackage 它判断了这个类的包名,包名不能以android.开头 它判断了这个类的包名,包名不能以java.开头
private boolean isInaccessibleViaGeneratedCode(Class annotationClass,
String targetThing, Element element) {
boolean hasError = false;
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
Set modifiers = element.getModifiers();
//验证方法修饰符不能为private和static。
if (modifiers.contains(PRIVATE) || modifiers.contains(STATIC)) {
error(element, "@%s %s must not be private or static. (%s.%s)",
annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
}
//验证包含类型不能为非Class
if (enclosingElement.getKind() != CLASS) {
error(enclosingElement, "@%s %s may only be contained in classes. (%s.%s)",
annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
}
//验证包含类的可见性并不是private。
if (enclosingElement.getModifiers().contains(PRIVATE)) {
error(enclosingElement, "@%s %s may not be contained in private classes. (%s.%s)",
annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
}
return hasError;
}
private boolean isBindingInWrongPackage(Class annotationClass,
Element element) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
String qualifiedName = enclosingElement.getQualifiedName().toString();
//它判断了这个类的包名,包名不能以android.开头
if (qualifiedName.startsWith(ANDROID_PREFIX)) {
error(element, "@%s-annotated class incorrectly in Android framework package. (%s)",
annotationClass.getSimpleName(), qualifiedName);
return true;
}
//它判断了这个类的包名,包名不能以java.开头
if (qualifiedName.startsWith(JAVA_PREFIX)) {
error(element, "@%s-annotated class incorrectly in Java framework package. (%s)",
annotationClass.getSimpleName(), qualifiedName);
return true;
}
return false;
}
7.6 看看parseBind中的parseBindMany方法 如下所示
private void parseBindMany(Element element, Map targetClassMap,
Set erasedTargetNames) {
//是否有错误,默认是false
boolean hasError = false;
//获取被包含的元素
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
//验证的类型是一个列表List或数组array。
TypeMirror elementType = element.asType();
//删除类型
String erasedType = doubleErasure(elementType);
TypeMirror viewType = null;
FieldCollectionViewBinding.Kind kind = null;
//比较获取的类型是否是ARRAY类型
if (elementType.getKind() == TypeKind.ARRAY) {
ArrayType arrayType = (ArrayType) elementType;
viewType = arrayType.getComponentType();
kind = FieldCollectionViewBinding.Kind.ARRAY;
} else if (LIST_TYPE.equals(erasedType)) {
DeclaredType declaredType = (DeclaredType) elementType;
List typeArguments = declaredType.getTypeArguments();
if (typeArguments.size() != 1) {
error(element, "@%s List must have a generic component. (%s.%s)",
Bind.class.getSimpleName(), enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
} else {
viewType = typeArguments.get(0);
}
kind = FieldCollectionViewBinding.Kind.LIST;
} else {
//如果都不是list或者array类型,那么直接抛出异常
throw new AssertionError();
}
if (viewType != null && viewType.getKind() == TypeKind.TYPEVAR) {
TypeVariable typeVariable = (TypeVariable) viewType;
viewType = typeVariable.getUpperBound();
}
//验证目标类型是否从视图扩展.
if (viewType != null && !isSubtypeOfType(viewType, VIEW_TYPE) && !isInterface(viewType)) {
error(element, "@%s List or array type must extend from View or be an interface. (%s.%s)",
Bind.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
hasError = true;
}
//如果有错误,执行结束
if (hasError) {
return;
}
// 收集实地信息.
String name = element.getSimpleName().toString();
int[] ids = element.getAnnotation(Bind.class).value();
if (ids.length == 0) {
error(element, "@%s must specify at least one ID. (%s.%s)", Bind.class.getSimpleName(),
enclosingElement.getQualifiedName(), element.getSimpleName());
return;
}
Integer duplicateId = findDuplicate(ids);
if (duplicateId != null) {
error(element, "@%s annotation contains duplicate ID %d. (%s.%s)", Bind.class.getSimpleName(),
duplicateId, enclosingElement.getQualifiedName(), element.getSimpleName());
}
assert viewType != null; // Always false as hasError would have been true.
String type = viewType.toString();
boolean required = isRequiredBinding(element);
BindingClass bindingClass = getOrCreateTargetClass(targetClassMap, enclosingElement);
FieldCollectionViewBinding binding = new FieldCollectionViewBinding(name, type, kind, required);
//将生成的BindingClass存入数组中
bindingClass.addFieldCollection(ids, binding);
erasedTargetNames.add(enclosingElement.toString());
}
7.7 回到bindingClass.brewJava()方法中 继续回到process代码中,思考write是做什么用的呢? 这个函数通过将我们绑定类的信息写入到文件外还负责创建绑定和创建解除绑定。在将绑定函数写入到文件后,整个编译器的注解方法就结束。
7.8 接下来看注解过程,bind方法 如图所示
我们可以看到最终都是调用这个方法
static void bind(Object target, Object source, ButterKnife.Finder finder) {
//获取class
Class targetClass = target.getClass();
try {
if (debug) Log.d(TAG, "Looking up view binder for " + targetClass.getName());
//通过findViewBinderForClass生成每个类
ButterKnife.ViewBinder viewBinder = findViewBinderForClass(targetClass);
if (viewBinder != null) {
//如果viewBinder不为空,则进行绑定
viewBinder.bind(finder, target, source);
}
} catch (Exception e) {
throw new RuntimeException("Unable to bind views for " + targetClass.getName(), e);
}
}
7.9 看注解过程中bind中的findViewBinderForClass 方法
private static ButterKnife.ViewBinder findViewBinderForClass(Class cls)
throws IllegalAccessException, InstantiationException {
//从内存中查找
ButterKnife.ViewBinder viewBinder = BINDERS.get(cls);
if (viewBinder != null) {
if (debug) Log.d(TAG, "HIT: Cached in view binder map.");
return viewBinder;
}
String clsName = cls.getName();
//检查是否为framework class
if (clsName.startsWith(ANDROID_PREFIX) || clsName.startsWith(JAVA_PREFIX)) {
if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
return NOP_VIEW_BINDER;
}
try {
//实例化“MainActivity$$ViewBinder”这样的类
Class viewBindingClass = Class.forName(clsName + ButterKnifeProcessor.SUFFIX);
//noinspection unchecked
viewBinder = (ButterKnife.ViewBinder) viewBindingClass.newInstance();
if (debug) Log.d(TAG, "HIT: Loaded view binder class.");
} catch (ClassNotFoundException e) {
if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
//异常,则去父类查找
viewBinder = findViewBinderForClass(cls.getSuperclass());
}
//放入内存并返回
BINDERS.put(cls, viewBinder);
return viewBinder;
}
其他
知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
领英:https://www.linkedin.com/in/chong-yang-049216146/
简书:http://www.jianshu.com/u/b7b2c6ed9284
csdn:http://my.csdn.net/m0_37700275
网易博客:http://yangchong211.blog.163.com/
新浪博客:http://blog.sina.com.cn/786041010yc
github:https://github.com/yangchong211
喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
脉脉:yc930211
360图书馆:http://www.360doc.com/myfiles.aspx
开源中国:https://my.oschina.net/zbj1618/blog
泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
邮箱:yangchong211@163.com
阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100239.headeruserinfo.3.dT4bcV
你可能感兴趣的:(设计模式)
建造者模式
智想天开
设计模式详解 建造者模式 嵌入式硬件 设计模式
公众号地址:建造者模式更多内容请关注公众号:智想天开1.什么是建造者模式?建造者模式是一种创建型设计模式,旨在通过将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。它允许一步步构建一个复杂对象,并且可以根据需要定制其内部组成部分。关键点:分步构建:将对象的构建过程分解为多个步骤,每个步骤负责构建对象的一个部分。封装构建过程:将构建过程封装在建造者类中,客户端无需了解具体的
中介者模式
智想天开
设计模式详解 中介者模式
原文地址:中介者模式更多内容请关注:智想天开1.中介者模式简介中介者模式(MediatorPattern)是一种行为型设计模式,它通过一个中介对象来封装一系列对象的交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,并且可以独立地改变它们之间的交互。该模式的核心思想是引入一个中介者对象来管理对象之间的通信,避免对象之间的直接依赖。关键点:集中管理:所有对象的交互都通过中介者进行,集中管理对
一个实例用全创建型模式-优化(冗余消除)
科学的发展-只不过是读大自然写的代码
java 算法 前端
1.关联链接上一篇:一个实例用全创建型模式-CSDN博客目录:《一个实例讲完23种设计模式》2.内容当前:单件+抽象工厂+创建者+工厂方法+优化需求:坦克大战创建两种坦克坦克类型射程速度b7070米时/70公里b5050米时/50公里设计说明1.抽象工厂承担了创建部件的任务2.创建者承担了讲部件组装的任务3.工厂方法类相当于创建者模式的导演,但是他是并未给用户提供选择创建者的接口。而是通过自己的多
22. 备忘录模式
智想天开
设计模式详解 备忘录模式
原文地址:备忘录模式更多内容请关注:智想天开1.备忘录模式简介备忘录模式(MementoPattern)是一种行为型设计模式,它允许在不暴露对象实现细节的情况下捕获和保存对象的内部状态,从而在未来需要时恢复对象到先前的状态。备忘录模式通过引入备忘录对象,实现了对象状态的保存与恢复,常用于实现撤销(Undo)功能。关键点:状态保存与恢复:在不破坏封装性的前提下,保存对象的内部状态,并在需要时恢复。封
Spring MVC笔记
@卡卡-罗特
spring mvc 笔记
01什么是SpringMVCSpringMVC是Spring框架中的一个核心模块,专门用于构建Web应用程序。它基于经典的MVC设计模式(Model-View-Controller),但通过Spring的特性(如依赖注入、注解驱动)大幅简化了开发流程。SpringMVC是什么?本质:一个基于Java的Web框架,帮助开发者快速、结构化地开发动态网站或RESTfulAPI。核心思想:将应用程序拆分为
【C++设计模式】第十六篇:迭代器模式(Iterator)
JuicyActiveGilbert
C++设计模式 c++ 设计模式 迭代器模式
注意:复现代码时,确保VS2022使用C++17/20标准以支持现代特性。遍历聚合对象的统一方式1.模式定义与用途核心思想迭代器模式:提供一种方法顺序访问聚合对象的元素,而无需暴露其内部表示。关键用途:1.统一遍历接口:为不同数据结构(如数组、链表、树)提供一致的遍历方式。2.支持多种遍历策略:前向、反向、条件过滤等。3.简化聚合类设计:将遍历逻辑从聚合类中分离。经典场景STL容器的迭代器(如st
架构师之路——设计模式篇(总览)
周努力.
设计模式 java
1.前言在1994年,由ErichGamma、RichardHelm、RalphJohnson和JohnVlissides四人合著出版了一本名为DesignPatterns-ElementsofReusableObject-OrientedSoftware(中文译名:设计模式-可复用的面向对象软件元素)的书,该书首次提到了软件开发中设计模式的概念。设计模式——这四个字不仅仅是一个通用技能的名称,更
一个轻量级的依赖注入容器实现
火凤凰--凤凰码路
java 开发语言
在现代软件开发中,依赖注入(DependencyInjection,DI)是一种重要的设计模式,用于降低组件之间的耦合度,提高代码的可维护性和可测试性。虽然Spring框架是目前最流行的依赖注入框架之一,但在某些场景下,我们可能需要一个更轻量级的解决方案。本文将通过分析一个名为MyContextHolder的类,探讨如何实现一个基于静态容器的依赖注入框架,并支持通过注解进行依赖注入。publicc
微服务设计模式--概述(笔记)
微服务设计模式
模式分为三组:基础设施相关模式:基础设施相关;应用基础设施相关:应用层面基础设施;应用相关模式组;各模式分解服务拆分模式根据业务能力分解模式根据子域分解模式通信相关通信风格服务发现可靠性事务性消息外部API数据一致性解决分布式日志,以及数据一致性;查询数据解决多个服务数据源获取数据;CQRS:命令查询职责隔离服务部署解决微服务如何部署;可食用虚拟机,容器,serverless技术;可观测性理解和诊
三大范式,让数据库更规范、高效!
码熔burning
MySQL 数据库 数据库 mysql
目录一、为什么要使用范式?二、第一范式(1NF)三、第二范式(2NF)四、第三范式(3NF)五、总结我的其他文章也讲解的比较有趣,如果喜欢博主的讲解方式,可以多多支持一下,感谢!了解MVCC请看:MVCC:多版本并发控制,让数据“时光倒流”的秘密!其他优质专栏:【SpringBoot】【多线程】【Redis】【✨设计模式专栏(已完结)】…等如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我
设计模式-行为型模式-中介者模式
繁星璀璨G
# 行为型模式 设计模式 中介者模式 c++
工程源码:c++设计模式-行为型模式-中介者模式https://download.csdn.net/download/qq_40788199/85763979码云:设计模式-行为型模式-中介者模式https://gitee.com/gongguixing/c-design-mode.git1、模式的定义与特点中介者(Mediator)模式的定义:定义一个中介对象来封装一系列对象之间的交互,使原有对
设计模式---中介者模式
星光技术人
C++基础与用法记录 设计模式 中介者模式
设计模式---中介者模式定义与设计思路中介者模式的引入:机场控制塔中介者模式的设计框架定义与设计思路定义:用一个中介对象来封装一系列对象交互。中介者使各对象不需要相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,属于行为型模式。设计思路:用一个中介对象来封装一系列的对象交互操作,中介者模式使得对象之间不需要显示的相互引用,从而使得系统或模块内部相互解耦,而且
设计模式之中介者模式
Forget the Dream
设计模式 设计模式 中介者模式 java c++
引言某个工作日的早晨,小A发现楼栋电梯停运了。他打开物业小程序提交报修单,短短10分钟后,楼栋公告屏就亮起了提示:“电梯故障已受理,预计2小时内修复”。这看似简单的流程背后,隐藏着一个精密的协作系统:物业中心在收到报修后同步触发:生成维修工单(自动派发给签约维保公司)启动临时安保预案(通知巡逻岗重点监控3栋)推送进度通知(居民小程序/短信/公告屏三端同步)维修完成时,系统继续联动:关闭电梯警示标识
软件开发基础-设计模式
奥德彪123
设计模式 设计模式
设计模式在软件开发中非常重要,尤其是在面试中经常被问到。以下是一些常见的设计模式,以及它们的应用案例:模式作用案例单例模式确保只有一个实例日志管理、数据库连接池工厂模式让子类决定实例化解析不同格式的文件(JSON、XML)适配器模式兼容不同接口旧系统迁移、新API适配代理模式控制访问权限控制、远程调用观察者模式事件触发订阅/发布、GUI事件策略模式动态切换算法支付方式、游戏AI1.创建型模式(Cr
侯捷C++设计模式总结
Aurora141592
设计模式 c++
面向对象设计原则依赖倒置原则开放封闭原则单一职责原则里氏替换原则接口隔离原则优先使用对象组合,而不是类继承封装变化点针对接口编程,而不是针对实现编程剩下的以后再补充
C++ 设计模式:建造者模式(Builder Pattern)
冀晓武
C++设计模式 c++ 设计模式 建造者模式
链接:C++设计模式链接:C++设计模式-工厂方法链接:C++设计模式-抽象工厂链接:C++设计模式-原型模式建造者模式(BuilderPattern)是一种创建型设计模式,它允许你分步骤创建复杂对象。与其他创建型模式不同,建造者模式不仅关注对象的创建,还关注对象的组装过程。1.问题分析在软件开发中,有时我们需要创建一个复杂对象,这个对象由多个部分组成,并且这些部分的构建过程可能非常复杂。直接使用
Mybatis中使用的设计模式
rice_88
Mybatis mybatis 设计模式
建造者模式这里讲得很清楚了深入浅出设计模式——建造者模式(BuilderPattern)在mybatis中,在解析配置文件的时候使用。Builder角色是org.apache.ibatis.builder.BaseBuilderConcreteBuilder角色就是它的实现类,分别负责解析不同类型的配置文件,包括org.apache.ibatis.builder.xml.XMLConfigBuil
【第17节】C++设计模式(行为模式)-Memento(备忘录)模式
攻城狮7号
c++版本设计模式 c++ 设计模式 备忘录模式
一、问题引出使用Memento模式实现撤销操作在软件开发中,用户在执行某些关键操作时,可能会希望有“撤销”功能,以便在操作失误时能够恢复到之前的状态。Memento模式正是为了解决这一问题而设计的。该模式允许在不破坏封装性的前提下,捕获并保存一个对象的内部状态,从而在需要时恢复该状态。二、Memento模式概述Memento模式的核心思想是在不暴露对象内部结构的情况下,保存对象的内部状态。通过这种
【C++设计模式】第十三篇:责任链模式(Chain of Responsibility)
JuicyActiveGilbert
C++设计模式 c++ 设计模式 责任链模式
注意:复现代码时,确保VS2022使用C++17/20标准以支持现代特性。动态传递请求的处理流水线1.模式定义与用途核心思想责任链模式:将多个处理对象连成一条链,请求沿链传递直至被处理。每个处理者可选择处理请求或转发给下一处理者。关键用途:1.解耦请求与处理:发送者无需知道具体处理者。2.动态调整处理流程:运行时增删处理节点(如日志过滤链、审批流程)。经典场景中间件处理HTTP请求(认证、限流、日
字节跳动C++客户端开发实习生内推-抖音基础技术
飞300
业界资讯 c++
智能手机爱好者和使用者,追求良好的用户体验;具有良好的编程习惯,代码结构清晰,命名规范;熟练掌握数据结构与算法、计算机网络、操作系统、编译原理等课程;熟练掌握C/C++/OC/Swift一种或多种语言,理解基本的设计模式;有深度参与开源项目或者自己独立开发过App上架App商城优先。内推链接(校招与实习均含):https://job.toutiao.com/campus/m/position?ex
Java代理
lyrhhhhhhhh
java 开发语言
在软件开发中,代理模式是一种非常常见的设计模式。它允许我们通过一个代理对象间接访问目标对象,从而在不修改目标对象的情况下增强其功能。代理模式广泛应用于日志记录、权限校验、事务管理、延迟加载等场景。本文将带你深入了解Java中的代理模式,包括静态代理和动态代理的实现方式。一、什么是代理给目标对象提供一个代理对象,并且由代理对象控制着对目标对象的引用在程序中,代理模式的核心思想是:代理对象:代替目标对
mybaties中使用的设计模式
大丈夫在世当日食一鲲
设计模式
一、创建型模式工厂模式应用场景:SqlSessionFactory负责创建SqlSession(数据库会话),通过不同参数生成不同配置的实例。例如,DefaultSqlSessionFactory根据事务隔离级别、自动提交等参数构建会话对象。实现方式:通过抽象工厂接口定义创建逻辑,子类实现具体对象的实例化。单例模式应用场景:Configuration类作为全局配置中心,通过getInstance(
C++设计模式总结
Dontla
C/C++ c++ 设计模式 开发语言
文章目录一、**创建型模式**(简化对象创建)1.**工厂模式**(FactoryPattern)2.**单例模式**(SingletonPattern)3.**建造者模式**(BuilderPattern)二、**结构型模式**(处理对象组合关系)4.**适配器模式**(AdapterPattern)5.**组合模式**(CompositePattern)6.**代理模式**(ProxyPatt
04.基于C++实现多线程TCP服务器与客户端通信
Chenyu_310
计算机网络 c++ tcp/ip 服务器 linux 网络 visualstudio 算法
基于C++实现多线程TCP服务器与客户端通信目录一、项目背景与目标二、从零开始理解网络通信三、相关技术背景知识1.守护进程(DaemonProcess)2.线程池(ThreadPool)3.RAII设计模式四、项目整体结构与逻辑五、核心模块详细分析1.TCP服务器模块2.线程池模块3.任务处理模块4.日志模块5.守护进程模块6.锁管理模块六、从实践到理论:关键设计模式与技术七、进阶主题与扩展思考八
白话设计模式之适配器模式:编程世界的接口“翻译官”
一杯年华@编程空间
白话设计模式 设计模式 适配器模式 数据库
白话设计模式之适配器模式:编程世界的接口“翻译官”大家好,软件开发的学习之旅充满挑战,设计模式作为其中重要的一环,常常让不少开发者感到困惑。我自己在学习过程中也走了不少弯路,所以特别希望能通过这篇文章,和大家一起深入了解适配器模式,在交流和探讨中共同进步,让设计模式不再是难以攻克的难题。一、从生活场景理解适配器模式在日常生活里,我们经常会遇到各种接口不匹配的情况,而适配器就像是一个神奇的“转换器”
了解Spring中常见的设计模式--责任链模式
tealala
java常用设计模式 设计模式 责任链模式
责任链模式(chainofreaponsiblityPattern):是将链中的每一个节点看作是一个对象,每一个节点对请求的处理不同(或者处理不同的请求),并且内部维护着下一个节点对象;一个请求进来,会从责任链的首部开始向下传递,直到有节点处理请求或者是走完整个链路;优点:1、将请求与处理进行解耦;2、链路中的节点只需要处理自己关心的请求,对于自己不关心的请求放给下一个节点进行处理;3、请求不需要
设计模式-责任链模式
会很甜
设计模式 设计模式 java servlet
目录一、引出问题二、责任链模式的概念和使用抽象处理器:用户名校验处理器:密码校验器:客户端调用:三、责任链模式+建造者模式四、责任链模式在源码运用五、总结本文通过图书馆管理系统中,用户名校验、密码校验、需要增加问题,每次都要增加if判断语句,将其改用责任链模式进行链式调用,为了让代码更加的优雅,我们使用之前学过的建造者模式就代码进行改造。接着我们会介绍责任链模式在我们常用的框架中的运用,最后是责任
《Head First 设计模式》例子的C++实现(2 观察者模式)
liyuanbhu
数据结构与算法 编程杂项 设计模式
最近在学习设计模式,用的是《HeadFirst设计模式》这本书。感觉这本书写的还是很不错的,深入浅出的介绍了各种常用的设计模式。唯一有点不方便的地方是这本书的例子全都是用的Java来实现的。而我主要是用C++。所以就动手将书上的代码用C++来实现了一遍。观察者模式首先是三个接口的代码://observer.h#ifndefOBSERVER_H#defineOBSERVER_HclassObserv
【SpringMVC】SpringMVC的启动过程与原理分析:从源码到实战
工一木子
原理分析 软件架构 SpringMVC SpringMVC 原理分析 MVC
SpringMVC的启动过程与原理分析:从源码到实战SpringMVC是Spring框架中用于构建Web应用的核心模块,它基于MVC(Model-View-Controller)设计模式,提供了灵活且强大的Web开发能力。本文将深入分析SpringMVC的启动过程、核心原理,并通过代码实战演示其工作流程。最后,我们还会探讨SpringMVC在JDK和Spring框架中的应用。一、SpringMVC
软件架构复用
Dragonlongbo
系统架构
软件架构复用是指在软件开发过程中,重新使用已有的软件架构设计、模式或组件,以提高开发效率、减少成本和保证质量的一种方法。它是软件复用的一种形式,但专注于更高层次的设计和结构。机会复用:在开发过程中,只要发现有可复用的资产,就对其进行复用系统复用:在开发之间进行规划,以决定哪些需要复用可复用的资产需求:可重复使用的需求文档或需求规范架构设计:可重复使用的系统架构或设计模式元素:代码模块、库或组件建模
Java序列化进阶篇
g21121
java序列化
1.transient
类一旦实现了Serializable 接口即被声明为可序列化,然而某些情况下并不是所有的属性都需要序列化,想要人为的去阻止这些属性被序列化,就需要用到transient 关键字。
escape()、encodeURI()、encodeURIComponent()区别详解
aigo
JavaScript Web
原文:http://blog.sina.com.cn/s/blog_4586764e0101khi0.html
JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:,decodeURI,decodeURIComponent 。
下面简单介绍一下它们的区别
1 escape()函
ArcgisEngine实现对地图的放大、缩小和平移
Cb123456
添加矢量数据 对地图的放大、缩小和平移 Engine
ArcgisEngine实现对地图的放大、缩小和平移:
个人觉得是平移,不过网上的都是漫游,通俗的说就是把一个地图对象从一边拉到另一边而已。就看人说话吧.
具体实现:
一、引入命名空间
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Controls;
二、代码实现.
Java集合框架概述
天子之骄
Java集合框架概述
集合框架
集合框架可以理解为一个容器,该容器主要指映射(map)、集合(set)、数组(array)和列表(list)等抽象数据结构。
从本质上来说,Java集合框架的主要组成是用来操作对象的接口。不同接口描述不同的数据类型。
简单介绍:
Collection接口是最基本的接口,它定义了List和Set,List又定义了LinkLi
旗正4.0页面跳转传值问题
何必如此
java jsp
跳转和成功提示
a) 成功字段非空forward
成功字段非空forward,不会弹出成功字段,为jsp转发,页面能超链接传值,传输变量时需要拼接。接拼接方式list.jsp?test="+strweightUnit+"或list.jsp?test="+weightUnit+&qu
全网唯一:移动互联网服务器端开发课程
cocos2d-x小菜
web开发 移动开发 移动端开发 移动互联 程序员
移动互联网时代来了! App市场爆发式增长为Web开发程序员带来新一轮机遇,近两年新增创业者,几乎全部选择了移动互联网项目!传统互联网企业中超过98%的门户网站已经或者正在从单一的网站入口转向PC、手机、Pad、智能电视等多端全平台兼容体系。据统计,AppStore中超过85%的App项目都选择了PHP作为后端程
Log4J通用配置|注意问题 笔记
7454103
DAO apache tomcat log4j Web
关于日志的等级 那些去 百度就知道了!
这几天 要搭个新框架 配置了 日志 记下来 !做个备忘!
#这里定义能显示到的最低级别,若定义到INFO级别,则看不到DEBUG级别的信息了~!
log4j.rootLogger=INFO,allLog
# DAO层 log记录到dao.log 控制台 和 总日志文件
log4j.logger.DAO=INFO,dao,C
SQLServer TCP/IP 连接失败问题 ---SQL Server Configuration Manager
darkranger
sql c windows SQL Server XP
当你安装完之后,连接数据库的时候可能会发现你的TCP/IP 没有启动..
发现需要启动客户端协议 : TCP/IP
需要打开 SQL Server Configuration Manager...
却发现无法打开 SQL Server Configuration Manager..??
解决方法: C:\WINDOWS\system32目录搜索framedyn.
[置顶] 做有中国特色的程序员
aijuans
程序员
从出版业说起 网络作品排到靠前的,都不会太难看,一般人不爱看某部作品也是因为不喜欢这个类型,而此人也不会全不喜欢这些网络作品。究其原因,是因为网络作品都是让人先白看的,看的好了才出了头。而纸质作品就不一定了,排行榜靠前的,有好作品,也有垃圾。 许多大牛都是写了博客,后来出了书。这些书也都不次,可能有人让为不好,是因为技术书不像小说,小说在读故事,技术书是在学知识或温习知识,有些技术书读得可
document.domain 跨域问题
avords
document
document.domain用来得到当前网页的域名。比如在地址栏里输入:javascript:alert(document.domain); //www.315ta.com我们也可以给document.domain属性赋值,不过是有限制的,你只能赋成当前的域名或者基础域名。比如:javascript:alert(document.domain = "315ta.com");
关于管理软件的一些思考
houxinyou
管理
工作好多看年了,一直在做管理软件,不知道是我最开始做的时候产生了一些惯性的思维,还是现在接触的管理软件水平有所下降.换过好多年公司,越来越感觉现在的管理软件做的越来越乱.
在我看来,管理软件不论是以前的结构化编程,还是现在的面向对象编程,不管是CS模式,还是BS模式.模块的划分是很重要的.当然,模块的划分有很多种方式.我只是以我自己的划分方式来说一下.
做为管理软件,就像现在讲究MVC这
NoSQL数据库之Redis数据库管理(String类型和hash类型)
bijian1013
redis 数据库 NoSQL
一.Redis的数据类型
1.String类型及操作
String是最简单的类型,一个key对应一个value,string类型是二进制安全的。Redis的string可以包含任何数据,比如jpg图片或者序列化的对象。
Set方法:设置key对应的值为string类型的value
Tomcat 一些技巧
征客丶
java tomcat dos
以下操作都是在windows 环境下
一、Tomcat 启动时配置 JAVA_HOME
在 tomcat 安装目录,bin 文件夹下的 catalina.bat 或 setclasspath.bat 中添加
set JAVA_HOME=JAVA 安装目录
set JRE_HOME=JAVA 安装目录/jre
即可;
二、查看Tomcat 版本
在 tomcat 安装目
【Spark七十二】Spark的日志配置
bit1129
spark
在测试Spark Streaming时,大量的日志显示到控制台,影响了Spark Streaming程序代码的输出结果的查看(代码中通过println将输出打印到控制台上),可以通过修改Spark的日志配置的方式,不让Spark Streaming把它的日志显示在console
在Spark的conf目录下,把log4j.properties.template修改为log4j.p
Haskell版冒泡排序
bookjovi
冒泡排序 haskell
面试的时候问的比较多的算法题要么是binary search,要么是冒泡排序,真的不想用写C写冒泡排序了,贴上个Haskell版的,思维简单,代码简单,下次谁要是再要我用C写冒泡排序,直接上个haskell版的,让他自己去理解吧。
sort [] = []
sort [x] = [x]
sort (x:x1:xs)
| x>x1 = x1:so
java 路径 配置文件读取
bro_feng
java
这几天做一个项目,关于路径做如下笔记,有需要供参考。
取工程内的文件,一般都要用相对路径,这个自然不用多说。
在src统计目录建配置文件目录res,在res中放入配置文件。
读取文件使用方式:
1. MyTest.class.getResourceAsStream("/res/xx.properties")
2. properties.load(MyTest.
读《研磨设计模式》-代码笔记-简单工厂模式
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
package design.pattern;
/*
* 个人理解:简单工厂模式就是IOC;
* 客户端要用到某一对象,本来是由客户创建的,现在改成由工厂创建,客户直接取就好了
*/
interface IProduct {
SVN与JIRA的关联
chenyu19891124
SVN
SVN与JIRA的关联一直都没能装成功,今天凝聚心思花了一天时间整合好了。下面是自己整理的步骤:
一、搭建好SVN环境,尤其是要把SVN的服务注册成系统服务
二、装好JIRA,自己用是jira-4.3.4破解版
三、下载SVN与JIRA的插件并解压,然后拷贝插件包下lib包里的三个jar,放到Atlassian\JIRA 4.3.4\atlassian-jira\WEB-INF\lib下,再
JWFDv0.96 最新设计思路
comsci
数据结构 算法 工作 企业应用 公告
随着工作流技术的发展,工作流产品的应用范围也不断的在扩展,开始进入了像金融行业(我已经看到国有四大商业银行的工作流产品招标公告了),实时生产控制和其它比较重要的工程领域,而
vi 保存复制内容格式粘贴
daizj
vi 粘贴 复制 保存原格式 不变形
vi是linux中非常好用的文本编辑工具,功能强大无比,但对于复制带有缩进格式的内容时,粘贴的时候内容错位很严重,不会按照复制时的格式排版,vi能不能在粘贴时,按复制进的格式进行粘贴呢? 答案是肯定的,vi有一个很强大的命令可以实现此功能 。
在命令模式输入:set paste,则进入paste模式,这样再进行粘贴时
shell脚本运行时报错误:/bin/bash^M: bad interpreter 的解决办法
dongwei_6688
shell脚本
出现原因:windows上写的脚本,直接拷贝到linux系统上运行由于格式不兼容导致
解决办法:
1. 比如文件名为myshell.sh,vim myshell.sh
2. 执行vim中的命令 : set ff?查看文件格式,如果显示fileformat=dos,证明文件格式有问题
3. 执行vim中的命令 :set fileformat=unix 将文件格式改过来就可以了,然后:w
高一上学期难记忆单词
dcj3sjt126com
word english
honest 诚实的;正直的
argue 争论
classical 古典的
hammer 锤子
share 分享;共有
sorrow 悲哀;悲痛
adventure 冒险
error 错误;差错
closet 壁橱;储藏室
pronounce 发音;宣告
repeat 重做;重复
majority 大多数;大半
native 本国的,本地的,本国
hibernate查询返回DTO对象,DTO封装了多个pojo对象的属性
frankco
POJO hibernate查询 DTO
DTO-数据传输对象;pojo-最纯粹的java对象与数据库中的表一一对应。
简单讲:DTO起到业务数据的传递作用,pojo则与持久层数据库打交道。
有时候我们需要查询返回DTO对象,因为DTO
Partition List
hcx2013
partition
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of th
Spring MVC测试框架详解——客户端测试
jinnianshilongnian
上一篇《Spring MVC测试框架详解——服务端测试》已经介绍了服务端测试,接下来再看看如果测试Rest客户端,对于客户端测试以前经常使用的方法是启动一个内嵌的jetty/tomcat容器,然后发送真实的请求到相应的控制器;这种方式的缺点就是速度慢;自Spring 3.2开始提供了对RestTemplate的模拟服务器测试方式,也就是说使用RestTemplate测试时无须启动服务器,而是模拟一
关于推荐个人观点
liyonghui160com
推荐系统 关于推荐个人观点
回想起来,我也做推荐了3年多了,最近公司做了调整招聘了很多算法工程师,以为需要多么高大上的算法才能搭建起来的,从实践中走过来,我只想说【不是这样的】
第一次接触推荐系统是在四年前入职的时候,那时候,机器学习和大数据都是没有的概念,什么大数据处理开源软件根本不存在,我们用多台计算机web程序记录用户行为,用.net的w
不间断旋转的动画
pangyulei
动画
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M
自定义annotation
sha1064616837
java enum annotation reflect
对象有的属性在页面上可编辑,有的属性在页面只可读,以前都是我们在页面上写死的,时间一久有时候会混乱,此处通过自定义annotation在类属性中定义。越来越发现Java的Annotation真心很强大,可以帮我们省去很多代码,让代码看上去简洁。
下面这个例子 主要用到了
1.自定义annotation:@interface,以及几个配合着自定义注解使用的几个注解
2.简单的反射
3.枚举
Spring 源码
up2pu
spring
1.Spring源代码
https://github.com/SpringSource/spring-framework/branches/3.2.x
注:兼容svn检出
2.运行脚本
import-into-eclipse.bat
注:需要设置JAVA_HOME为jdk 1.7
build.gradle
compileJava {
sourceCompatibilit
利用word分词来计算文本相似度
yangshangchuan
word word分词 文本相似度 余弦相似度 简单共有词
word分词提供了多种文本相似度计算方式:
方式一:余弦相似度,通过计算两个向量的夹角余弦值来评估他们的相似度
实现类:org.apdplat.word.analysis.CosineTextSimilarity
用法如下:
String text1 = "我爱购物";
String text2 = "我爱读书";
String text3 =