# reflex
**Repository Path**: amaosir/reflex
## Basic Information
- **Project Name**: reflex
- **Description**: 设计模式
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-06-14
- **Last Updated**: 2022-03-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
1. 什么是反射、反射优缺点
2. 反射的用途/反射应用场景
3. 反射调用方法/给属性赋值
4. 反射如何越过泛型检查
5. 什么是注解/注解生效的原理
6. 自定义注解实现API接口限流框架
7. 自定义注解实现事务注解
### 1. [什么是Java反射](docs/reflex.md)
1. 就是正在运行,动态获取这个类的所有信息。
### 2. 反射机制的优缺点
第三方框架---创建对象 不是直接new 反射机制创建
目的:提供开发者能够更好封装框架实现扩展功能。
在一个类中 定义了一个私有属性/方法 反射机制破解私有属性
1. 优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2. 缺点:
1. 反射会消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射;
2. 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
### 2. 反射机制的作用
1. 反编译:.class-->.java
2. 通过反射机制访问java对象的属性,方法,构造方法等;
3. JDBC加载驱动连接 class.forname
Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动
4.Spring容器框架IOC实例化对象
5. 自定义注解生效(反射+Aop)
6. 第三方核心的框架 mybatis orm
### 4. 反射技术的使用
1. Class类 代表类的实体,在运行的Java应用程序中表示类和接口
2. Field类 代表类的成员变量(成员变量也称为类的属性)
3. Method类 代表类的方法
4. Constructor类 代表类的构造方法
1. getField、getMethod和getCostructor方法可以获得指定名字的域、方法和构造器。
2. getFields、getMethods和getCostructors方法可以获得类提供的public域、方法和构造器数组,其中包括超类的共有成员。
3. getDeclatedFields、getDeclatedMethods和getDeclaredConstructors方法可以获得类中声明的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员。
### 3.反射机制获取类有三种方法
```java
// 方式一
Class userEntityClass1 = UserEntity.class;
UserEntity userEntity1 = userEntityClass1.newInstance();
// 方式二
Class> userEntityClass2 = Class.forName("com.mao.entity.UserEntity");
UserEntity userEntity2 = (UserEntity) userEntityClass2.newInstance();
// 方式三
UserEntity userEntity = new UserEntity();
Class userEntityClass3 = userEntity.getClass();
```
1. Class.forName("类的完整路径")
```
// 1.实例化对象 -- 无参构造函数
// UserEntity userEntity = new UserEntity();
// userEntity.userName = "猫头鹰";
// System.out.println(userEntity.userName);
// 2. 使用 Java 的反射机制创建对象 类的完整路径
Class> forName = Class.forName("com.mao.entity.UserEntity");
// 3. 使用反射机制创建对象
UserEntity userEntity = (UserEntity) forName.newInstance();
userEntity.userName = "反射对象";
System.out.println(userEntity.userName);
// 4. 反射的应用场景 jdbc连接、SpringIOC hibernate、mybatis
// 5. 使用反射机制 获取类的信息
Method[] methods = forName.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
// 6. 获取类的属性
Field[] fields = forName.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
```
### 4. 反射创建api
|方法名称| 作用
---|---
|getDeclaredMethods []| 获取该类的所有方法
|getReturnType()| 获取该类的返回值
|getParameterTypes()| 获取传入参数
|getDeclaredFields() |获取该类的所有字段
|setAccessible |允许访问私有成员
### 5. 注解
1. 什么是注解:
注解用来给类声明附加额外信息,可以标注在类、字段、方法等上面,编译器、JVM以及开
2. 常用注解
```
@Override 只能标注在子类覆盖父类的方法上面,有提示的作用
@Deprecated 标注在过时的方法或类上面,有提示的作用
@SuppressWarnings("unchecked") 标注在编译器认为有问题的类、方法等上面,用来取消编译器的警告提示,警告类型有serial、unchecked、unused、all
@Target(ElementType.METHOD) // 指定新注解可以标注在方法上
@Retention(RetentionPolicy.RUNTIME) // 指定新注解保留到程序运行时期
@Inherited // 指定新注解标注在父类上时可被子类继承
public @interface MayiktName {
public String name();
}
自定义注解 运行 :反射+aop
```
3. 元注解:
元注解用来在声明新注解时指定新注解的一些特性
```java
@Target 指定新注解标注的位置,比如类、字段、方法等,取值有ElementType.Method等
@Retention 指定新注解的信息保留到什么时候,取值有RetentionPolicy.RUNTIME等
@Inherited 指定新注解标注在父类上时可被子类继承
```
4. 注的 Target
```java
TYPE:类、接口(包括注解类型)和枚举的声明
FIELD:字段声明(包括枚举常量)
METHOD:方法声明
PARAMETER:参数声明
CONSTRUCTOR:构造函数声明
LOCAL_VARIABLE:本地变量声明
ANNOTATION_TYPE:注解类型声明
PACKAGE:包声明
TYPE_PARAMETER:类型参数声明,JavaSE8引进,可以应用于类的泛型声明之处
TYPE_USE:JavaSE8引进,此类型包括类型声明和类型参数声明
```
### 5.设计模式
常用的:工厂方法模式、抽象工厂模式、单例模式、原型模式、
适配器模式、装饰器模式、代理模式、外观模式、组合模式、策略模式、模板方法模式、观察者模式
1. 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
2. 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
3. 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
### 6. 设计模式的六大原则
1. 开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2. 里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
3. 依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
4. 迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
5. 合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
### 6. [单例设计模式](docs/singletonMode.md)
1. 什么是单例:
保证一个类只有一个实例,并且提供一个访问该全局访问点
2. 单例优缺点
1. 优点:
1. 在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例
2. 单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
3. 提供了对唯一实例的受控访问。
4. 由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
5. 允许可变数目的实例。
6. 避免对共享资源的多重占用。
2. 缺点:
1. 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2. 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3. 单例类的职责过重,在一定程度上违背了“单一职责原则”。
4. 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
### 7. 单例创建方式
1. 饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。
2. 懒汉式: 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
3. 静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
4. 枚举单例: 使用枚举实现单例模式 优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞, 缺点没有延迟加载。
5. 双重检测锁方式 (因为JVM本质重排序的原因,可能会初始化多次,不推荐使用)
```java
/**
* 饿汉模式
*/
public class User02 {
// 类初始化的时候就会创建对象,天生线程安全,调用效率比较高,如果不适用对象的时候,就会浪费内存
private static final User01 user01 = new User01();
// 1. 将构造函数私有化
private User01() {
}
public static User01 getInstance() {
return user01;
}
//
public static void main(String[] args) {
User01 u1 = User01.getInstance();
User01 u2 = User01.getInstance();
System.out.println(u1 == u2);
}
}
```
---
```java
/**
* 懒汉式
*/
public class User02 {
//懒汉式:类初始化时,不会创建该对象,正真需要时,才会加载(创建),天生线程不安全,需要解决线程安全问题,所以效率比较低。
private static User02 user02;
private User02() {
}
// 线程安全 效率低
public static synchronized User02 getInstance() {
if (user02 == null) {
user02 = new User02();
}
return user02;
}
public static void main(String[] args) {
User02 u1 = User02.getInstance();
User02 u2 = User02.getInstance();
System.out.println(u1 == u2);
}
}
```
```java
/**
* 静态内部类
*/
public class User03 {
private User03() {
System.out.println("初始化...");
}
public static class UserClassInstance {
private static final User03 user03 = new User03();
}
public static User03 getInstance() {
System.out.println("getInstance");
return UserClassInstance.user03;
}
public static void main(String[] args) {
User03 u1 = User03.getInstance();
User03 u2 = User03.getInstance();
System.out.println(u1 == u2);
}
}
```
```java
/**
* 枚举单例
*/
public class User04 {
private User04() {
}
public static User04 getInstance() {
return SingletonUserEnum.INSTANCE.getInstance();
}
/**
* 本身枚举就是单例的
*/
static enum SingletonUserEnum {
INSTANCE;
private User04 user04;
private SingletonUserEnum() {
// 只会执行一次
user04 = new User04();
}
public User04 getInstance() {
return user04;
}
}
public static void main(String[] args) {
User04 u1 = User04.getInstance();
User04 u2 = User04.getInstance();
System.out.println(u1 == u2);
}
}
```
---
### 8. 工厂模式
1. 什么是工厂模式: 实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂模式
2. 工厂模式好处
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。
将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
3. 工厂模式分类
1. 简单工厂模式: 简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。
### 9. 简单工厂模式
1. 简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。

2. 单工厂的优点/缺点
1. 优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
2. 缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则
```java
public interface Car {
void run();
}
```
```java
/**
* 比亚迪汽车
*/
public class BydCar implements Car {
@Override
public void run() {
System.out.println("比亚迪汽车...");
}
}
```
```java
/**
* 吉利汽车
*/
public class JiliCar implements Car {
@Override
public void run() {
System.out.println("吉利汽车...");
}
}
```
```java
/**
* 汽车厂(4S店)
*/
public class CarFactory {
public static Car createCar(String name) {
if (StringUtils.isEmpty(name)) {
return null;
}
if ("比亚迪".equals(name)) {
return new BydCar();
}
if ("吉利".equals(name)) {
return new JiliCar();
}
return null;
}
}
```
```java
public class Client {
public static void main(String[] args) {
Car bydCar = CarFactory.createCar("比亚迪");
Car jiliCar = CarFactory.createCar("吉利");
bydCar.run();
jiliCar.run();
}
}
```
### 10. 工厂方法模式
1. 什么是工厂方法模式: 工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,

```java
public interface Car {
void run();
}
```
```java
/**
* 比亚迪汽车
*/
public class BydCar implements Car {
@Override
public void run() {
System.out.println("比亚迪汽车...");
}
}
```
```java
/**
* 吉利汽车
*/
public class JiliCar implements Car {
@Override
public void run() {
System.out.println("吉利汽车...");
}
}
```
```java
/**
* 汽车厂(4S店)
*/
public interface CarFactory {
Car createCar(String name);
}
```
```java
/**
* 比亚迪汽车4S店销售
*/
public class BydFactory implements CarFactory {
@Override
public Car createCar(String name) {
return new BydCar();
}
}
```
```java
/**
* 吉利汽车4S店销售
*/
public class JiLiFactory implements CarFactory {
@Override
public Car createCar(String name) {
return new JiliCar();
}
}
```
```java
public class Client {
public static void main(String[] args) {
CarFactory carFactory = new BydFactory();
Car car = carFactory.createCar("比亚迪");
car.run();
JiLiFactory jiLiFactory = new JiLiFactory();
Car jiLiCar = jiLiFactory.createCar("吉利");
jiLiCar.run();
}
}
```
### 11. 抽象工厂模式
1. 什么是抽象工厂模式:
抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。


```java
/**
* 发动机
*/
public interface Engine {
void run();
void start();
}
class EngineA implements Engine {
@Override
public void run() {
System.out.println("发送机转速快...");
}
@Override
public void start() {
}
}
class EngineB implements Engine {
@Override
public void run() {
System.out.println("发动机转速慢...");
}
@Override
public void start() {
}
}
```
```java
/**
* 座椅
*/
public interface Chair {
void run();
}
class ChairA implements Chair {
@Override
public void run() {
System.out.println("自动加热...");
}
}
class ChairB implements Chair {
@Override
public void run() {
System.out.println("不能加热...");
}
}
```
```java
/**
* 包装厂
*/
public interface CarFactory {
/**
* 创建发动机
*
* @return 发动机
*/
Engine createEngine();
/**
* 创建座椅
*
* @return 座椅
*/
Chair createChair();
}
```
```java
public class JiLiFactory implements CarFactory{
@Override
public Engine createEngine() {
return new EngineA();
}
@Override
public Chair createChair() {
return new ChairA();
}
}
```
```java
public class Client {
public static void main(String[] args) {
CarFactory jiLiFactory = new JiLiFactory();
Engine engineA = jiLiFactory.createEngine();
Chair chairA = jiLiFactory.createChair();
engineA.run();
engineA.start();
chairA.run();
}
}
```
---
### 12. [代理模式](docs/proxy.md)
1. 什么是代理模式:
通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现) ,AOP核心技术面向切面编程。

2. 代理模式应用场景:
SpringAOP、事物原理、日志打印、权限控制、远程调用、安全代理 可以隐蔽真实角色
3. 代理的分类:
1. 静态代理(静态定义代理类)
2. 动态代理(动态生成代理类)
3. Jdk自带动态代理
4. Cglib 、javaassist(字节码操作库)
**4. 静态代理**
1. 什么是静态代理:
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
```java
public interface IUserDao {
void add();
}
```
```java
public class IUserDaoImpl implements IUserDao{
@Override
public void add() {
System.out.println("add方法...");
}
}
```
```java
public class UserDaoProxy implements IUserDao {
private IUserDao iUserDao;
public UserDaoProxy(IUserDao iUserDao) {
this.iUserDao = iUserDao;
}
@Override
public void add() {
System.out.println("开启事务...");
iUserDao.add();
System.out.println("提交事务...");
}
}
```
```java
/**
* 静态代理,静态代理是需要生产代理对象的
*/
public class Demo01 {
public static void main(String[] args) {
IUserDao iUserDao = new IUserDaoImpl();
UserDaoProxy userDaoProxy = new UserDaoProxy(iUserDao);
userDaoProxy.add();
}
}
```
**5. 动态代理**
1. 什么是动态代理
1. 代理对象,不需要实现接口
2. 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3. 动态代理也叫做:JDK代理,接口代理
2. JDK动态代理
1. 原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下)
2. 实现方式:
1. 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
3. 缺点:jdk动态代理,必须是面向接口,目标业务类必须实现接口
```java
/**
* 每次生成动态代理类对象时,实现了InvocationHandler接口的调用处理器对象
*/
public class InvocationHandlerImpl implements InvocationHandler {
private Object target;// 这其实业务实现类对象,用来调用具体的业务方法
// 通过构造函数传入目标对象
public InvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用开始处理");
Object result = method.invoke(target, args);
System.out.println("调用结束处理");
return result;
}
public static void main(String[] args) {
IUserDao iUserDao = new IUserDaoImpl();
InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(iUserDao);
// 获取类加载器
ClassLoader classLoader = iUserDao.getClass().getClassLoader();
// 获取当前实现的接口
Class>[] interfaces = iUserDao.getClass().getInterfaces();
// 主要装载器、一组接口及调用处理动态代理实例
IUserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
newProxyInstance.add();
}
}
```
3. CGLIB动态代理
1. 原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
2. 什么是CGLIB动态代理
- 使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码
```java
public class CglibProxy implements MethodInterceptor {
private Object targetObject;
// 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
public Object getInstance(Object target) {
// 设置需要创建子类的类
this.targetObject = target;
// 操作字节码生成虚拟的子类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事物");
Object result = methodProxy.invoke(targetObject, objects);
System.out.println("关闭事物");
// 返回代理对象
return result;
}
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
IUserDao iUserDao = (IUserDao) cglibProxy.getInstance(new IUserDaoImpl());
iUserDao.add();
}
}
```
4. CGLIB动态代理与JDK动态区别
- java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
Spring中。
1. 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2. 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3. 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
---
### 1. 建造者模式
1. 什么是建造者模式

1. 建造者模式:是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。
建造者模式通常包括下面几个角色:
1. Builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
2. ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。
3. Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
4. Product:要创建的复杂对象。
2. 建造者应用场景
1. 去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
19元每周三 汉堡+可乐+薯条=套餐可能会发生改变。
2. JAVA 中的 StringBuilder 数组(单个字符)字整合在一起 字符串
3. 使用场景:
1. 需要生成的对象具有复杂的内部结构。
2. 需要生成的对象内部属性本身相互依赖。
**与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。**
4. 实际案例 :这里以游戏开发中人物的构造过程为例。在游戏中创建一个形象时,需要对每个部位进行创建。简化而言,需要创建头部,身体和四肢。
头部、体部、四肢
```java
/**
* @author mao
* @date 2021-06-26
* description 人物对象
*/
public class Person {
/**
* 头部
*/
private String head;
/**
* 体部
*/
private String body;
/**
* 尾部
*/
private String foot;
public String getHead() {
return head;
}
public void setHead(String head) {
this.head = head;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getFoot() {
return foot;
}
public void setFoot(String foot) {
this.foot = foot;
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
* description 给出一个抽象接口,以规范产品对象的各个组成成分的建造。
* 这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建
*/
public interface PersonBuilder {
/**
* 构建头部
*/
void buildHead();
/**
* 构建体部
*/
void buildBody();
/**
* 构建尾部
*/
void buildFoot();
/**
* 组织人物
*
* @return 人物
*/
Person buildPerson();
}
```
```java
/**
* @author mao
* @date 2021-06-26
* description 实现Builder接口,创建美国人。 在建造过程完成后,提供产品的实例
*/
public class ManBuilder implements PersonBuilder {
private Person person;
public ManBuilder() {
this.person = new Person();
}
@Override
public void buildHead() {
person.setHead("美国人,头部,鼻子尖...");
}
@Override
public void buildBody() {
person.setBody("美国人,体部,块头大...");
}
@Override
public void buildFoot() {
person.setFoot("美国人,尾部,腿长...");
}
@Override
public Person buildPerson() {
return person;
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
* description 实现Builder接口,创建日本人。 在建造过程完成后,提供产品的实例
*/
public class JpBuilder implements PersonBuilder {
private Person person;
public JpBuilder() {
this.person = new Person();
}
@Override
public void buildHead() {
person.setHead("日本人,头部,圆脸...");
}
@Override
public void buildBody() {
person.setBody("日本人,体部,块头小...");
}
@Override
public void buildFoot() {
person.setFoot("日本人,尾部,腿短...");
}
@Override
public Person buildPerson() {
return person;
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
* description 调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建
*/
public class PersonDirector {
public Person constructPerson(PersonBuilder personBuilder) {
personBuilder.buildHead();
personBuilder.buildBody();
personBuilder.buildFoot();
return personBuilder.buildPerson();
}
public static void main(String[] args) {
PersonDirector personDirector = new PersonDirector();
// 构建美国人
Person person = personDirector.constructPerson(new ManBuilder());
System.out.println(person.getHead());
System.out.println(person.getBody());
System.out.println(person.getFoot());
// 构建日本人
Person person1 = personDirector.constructPerson(new JpBuilder());
System.out.println(person1.getHead());
System.out.println(person1.getBody());
System.out.println(person1.getFoot());
}
}
```
## 2. 模板方法
1. 什么是模板方法
1. 模板方法模式:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的
重复代码全部在父类里面,不同业务的,使用抽象方法,抽取给子类进行实现。抽取过程---抽象方法。
某些特定步骤。
2. 核心:处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,我们采用工厂方法模式,将这个节点的代码实现转移给
子类完成。即:处理步骤在父类中定义好,具体的实现延迟到子类中定义。
说白了,就是将一些相同操作的代码,封装成一个算法的骨架。核心的部分留在子类中操作,在父类中只把那些骨架做好。
3. 例如:
1. 去银行办业务,银行给我们提供了一个模板就是:先取号,排对,办理业务(核心部分我们子类完成),给客服人员评分,完毕。
这里办理业务是属于子类来完成的,其他的取号,排队,评分则是一个模板。
2. 去餐厅吃饭,餐厅给提供的一套模板就是:先点餐,等待,吃饭(核心部分我们子类完成),买单
这里吃饭是属于子类来完成的,其他的点餐,买单则是餐厅提供给我们客户的一个模板。

```java
/**
* @author mao
* @date 2021-06-26
*/
public abstract class SendMessage {
public void headLog() {
System.out.println("调用运营商开始记录日志...");
}
public void footLog() {
System.out.println("调用运营商结束记录日志...");
}
/**
* 调用不同运营商发送短信
*/
public abstract void httpRequest();
/**
* 发送短信
*/
public void sendMessage() {
headLog();
httpRequest();
footLog();
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
*/
public class YiDong extends SendMessage{
@Override
public void httpRequest() {
System.out.println("http://yidong...");
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
*/
public class LianTong extends SendMessage{
@Override
public void httpRequest() {
System.out.println("http://liantong...");
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
*/
public class ClientTemplate {
public static void main(String[] args) {
YiDong yiDong = new YiDong();
yiDong.sendMessage();
LianTong lianTong = new LianTong();
lianTong.sendMessage();
}
}
```
### 3. 适配模式
1. 什么是适配器
在设计模式中,适配器模式(英语:adapter pattern)有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。
2. 适配器分类
适配器分为,类适配器、对象适配、接口适配方式;
类适配器方式采用继承方式,对象适配方式使用构造函数传递
3. 适配器案例
我们就拿日本电饭煲的例子进行说明,日本电饭煲电源接口标准是110V电压,而中国标准电压接口是220V,所以要想在中国用日本电饭煲,需要一个电源转换器。
```java
/**
* @author mao
* @date 2021-06-26
* 中国220V电源
*/
public interface Cn220vInterface {
/**
* 连接电源
*/
void connect();
}
```
```java
/**
* @author mao
* @date 2021-06-26
*/
public class Cn220vInterfaceImpl implements Cn220vInterface {
@Override
public void connect() {
System.out.println("中国220V电源开始连接...");
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
* 日本110V电源
*/
public interface Jp110vInterface {
/**
* 连接电源
*/
void connect();
}
```
```java
/**
* @author mao
* @date 2021-06-26
*/
public class Jp110vInterfaceImpl implements Jp110vInterface {
@Override
public void connect() {
System.out.println("日本110V电源开始连接...");
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
* 日本电饭煲
*/
public class ElectricCooker {
private Jp110vInterface jp110vInterface;
public ElectricCooker(Jp110vInterface jp110vInterface) {
this.jp110vInterface = jp110vInterface;
}
/**
* 电饭煲开始工作
*/
public void cook() {
jp110vInterface.connect();
System.out.println("电饭煲开始工作...");
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
* 适配器 传入中国220V电源
*/
public class PowerAdaptor implements Jp110vInterface{
private Cn220vInterface cn220vInterface;
public PowerAdaptor(Cn220vInterface cn220vInterface) {
this.cn220vInterface = cn220vInterface;
}
@Override
public void connect() {
cn220vInterface.connect();
}
}
```
```java
/**
* @author mao
* @date 2021-06-26
*/
public class AdaptorTest {
public static void main(String[] args) {
// 中国220V电源
Cn220vInterfaceImpl cn220vInterface = new Cn220vInterfaceImpl();
// 适配器
PowerAdaptor powerAdaptor = new PowerAdaptor(cn220vInterface);
// 电饭煲
ElectricCooker electricCooker = new ElectricCooker(powerAdaptor);
electricCooker.cook();
}
}
```
### 4. 外观模式
1. 什么是外观模式
外观模式(Facade Pattern)门面模式,隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。
这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

### 5. 原型模式
1. 什么是原型模式
克隆
原型模式是一个创建型的模式。原型二字表明了改模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。
原型模式应用场景
1. 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
2. 通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。
3. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
4. Spring框架中的多例就是使用原型。
2. 原型模式UML类图(通用)
2. 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:
1. 实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
2. 重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此Prototype类需要将clone方法的作用域修改为public类型。
3. 原型模式分为浅复制和深复制
1. 浅复制 —-只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做“(浅复制)浅拷贝”,换句话说,浅复制仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。
2. 深复制 —-在计算机中开辟了一块新的内存地址用于存放复制的对象。
```java
/**
* @author mao
* @date 2021-06-27
*/
public class Book implements Cloneable{
/**
* 标题
*/
private String title;
/**
* 图片列表
*/
private ArrayList image = new ArrayList<>();
@Override
protected Object clone() throws CloneNotSupportedException {
Book book = (Book) super.clone();
// 深复制
book.setImage((ArrayList) image.clone());
return book;
}
public void addImage(String img) {
image.add(img);
}
/**
* 打印内容
*/
public void showBook() {
System.out.println("-------start--------");
System.out.println("title:" + this.title);
for (String img : image) {
System.out.println("image name:" + img);
}
System.out.println("-------end--------");
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ArrayList getImage() {
return image;
}
public void setImage(ArrayList image) {
this.image = image;
}
}
```
```java
/**
* @author mao
* @date 2021-06-27
*/
public class BookTest {
public static void main(String[] args) throws CloneNotSupportedException {
Book book1 = new Book();
book1.setTitle("图书1");
book1.addImage("图片1");
book1.showBook();
Book book2 = (Book) book1.clone();
book2.setTitle("图书2");
book2.addImage("图片2");
book2.showBook();
book1.showBook();
}
}
```
### 6. 策略模式
1. 什么是策略模式
定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
2. 策略模式由三种角色组成
3. 策略模式应用场景:
策略模式的用意是针对一组算法或逻辑,将每一个算法或逻辑封装到具有共同接口的独立的类中,从而使得它们之间可以相互替换。策略模式使得算法或逻辑可以在不影响到客户端的情况下发生变化。说到策略模式就不得不提及OCP(Open Closed Principle) 开闭原则,即对扩展开放,对修改关闭。策略模式的出现很好地诠释了开闭原则,有效地减少了分支语句。
```java
/**
* @author by maotouying
* @Classname Strategy001
* @Description 策略模式 会员分为3种等级 铂金会员 黄金会员 普通会员 获取价格都不一样
* @Date 2021/7/8 21:07
*/
public class Strategy001 {
public static void main(String[] args) {
Context context;
context = new Context(new StrategyA());
context.algorithmInterface();
context = new Context(new StrategyB());
context.algorithmInterface();
context = new Context(new StrategyC());
context.algorithmInterface();
}
}
```
```java
/**
* @author by maotouying
* @Classname Strategy
* @Description 策略模式 定义抽象方法 所有支持公共接口
* @Date 2021/7/8 21:53
*/
public abstract class Strategy {
/**
* 算法方法
*/
abstract void algorithmInterface();
}
class StrategyA extends Strategy {
@Override
void algorithmInterface() {
System.out.println("普通会员算法A");
}
}
class StrategyB extends Strategy {
@Override
void algorithmInterface() {
System.out.println("黄金会员算法B");
}
}
class StrategyC extends Strategy {
@Override
void algorithmInterface() {
System.out.println("铂金会员算法C");
}
}
/**
* 使用上下文维护算法策略
*/
class Context {
Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void algorithmInterface(){
strategy.algorithmInterface();
}
}
```