七大原则
首先理解粒度的概念:功能的细化程度,粒度大说明区分的很细,粒度小说明功能区分不大
单一职责原则
包子工厂他就只生产包子,不生产别的
一个模块功能太多,系统稳定性减低
很多其他模块使用到它,发生一点改变,可能影响整个系统
(改一个变量,有可能影响方法)
开闭原则
开:允许可以拓展功能(提供方)
闭:修改关闭(使用方)
可以修改,但是需要再不需要改现有代码的情况下去拓展功能!
因为修改现有的代码可能会给现有的代码带来错误
(工厂模式中,简单工厂模式修改代码这种就是不对的)
里氏替换原则
1.子类继承父类,只有当行为一直才能使用继承
2.乱用继承,破坏了父类的结构,继承的体系被破环
3.解决方法,使用组合、聚合等方式代替继承
核心就是两方面:
1.继承不能乱用,没有特别重要的共性,就不要继承了
原因:继承带来的也有耦合,子类与父类就有了耦合关系
2.在子类继承父类后,对于父类已经实现好的代码,应该尽可能不要去修改他,
(修改后可能是2破坏了父类的结构,继承的体系被破环)可以尽量的使用其他方式,比如组合聚合依赖
接口隔离原则
eg:对一个接口,他有很多实现类,此时需要对接口的粒度降低,有需要的时候:细化为多个接口,让类要用什么功能就实现什么接口,让依赖这个类的对象更好的调用
即
一个类对另一个类的依赖应该建立在最小的接口上。
依赖倒转原则
面向接口编程
在应用的时候调用接口的实现,但真正的实现由接口的实现类去完成
调用实现类的方法:(实现接口隔离原则的依赖的方法):
1.构造方法
2.set方法
3.给一个参数,这个参数就是接口,输入
若利用组合,
比如ford的车改变了,组合的自动车也要跟着改变
对拓展、修改不方便
不符合开闭原则
因此:细节应该依赖于抽象,面向接口编程
合成复用原则
尽量使用合成/聚合,不是使用继承
迪米特法则
也叫知道最少原则,调用别人的方法,就不要去知道别人具体怎么干
类与类之间相互依赖时,对他依赖的类,知道的越少越好(可以减低耦合和安全)
七大原则总结:
利用以上原则就行
代码重构(看似功能没改变,但确实更好了)
代码就可以更加优秀,可维护性、耦合内聚、便于理解,便于分析错误
具体代码在尚硅谷的文档里:有Java基础阅读没问题,也可以去B站看视频
链接:https://pan.baidu.com/s/113Kz1-QShIZkhK7IkqqRtw
提取码:z313
创建者模型
工厂模式
简单工厂模式
工厂里提供很多方法,不同方法新建不同对象
工厂方法模式
抽象工厂模式
抽象工厂模式代码:
实现功能:小米工厂有小米手机和小米电脑,苹果工厂有苹果手机和苹果电脑
package factory.factory;
import factory.product.Computer;
import factory.product.Phone;
/**
* @Author: WYF
* @Description: 工厂接口
* @Create: 2020-04-06 16:03
* @Version: 1.0
*/
public interface Factory {
/**
* 建立电脑
*
* @Param void
* @return factory.product.Computer
*/
Computer createComputer();
/**
* 建立手机
*
* @Param void
* @return factory.product.Phone
*/
Phone createPhone();
}
小米工厂
package factory.factory;
import factory.product.Computer;
import factory.product.MiComputer;
import factory.product.MiPhone;
import factory.product.Phone;
public class MiFactory implements Factory {
@Override
public Computer createComputer() {
return new MiComputer();
}
@Override
public Phone createPhone() {
return new MiPhone();
}
}
苹果工厂
package factory.factory;
import factory.product.Computer;
import factory.product.IComputer;
import factory.product.IPhone;
import factory.product.Phone;
public class IFactory implements Factory {
@Override
public Computer createComputer() {
return new IComputer();
}
@Override
public Phone createPhone() {
return new IPhone();
}
}
电脑接口
package factory.product;
/**
* @Author: WYF
* @Description: 电脑接口
* @Create: 2020-04-06 15:48
* @Version: 1.0
*/
public interface Computer {
/**
* @Description: 电脑功能,用来玩
* @Param: []
* @Return: void
* @Author: WYF
* @Date: 2020/4/6 15:49
*/
void play();
/**
* @Description: 电脑功能,用来学习
* @Param: []
* @Return: void
* @Author: WYF
* @Date: 2020/4/6 15:49
*/
void study();
}
苹果电脑
package factory.product;
public class IComputer implements Computer {
@Override
public void play() {
System.out.println(this.getClass()+"玩 苹果电脑");
}
@Override
public void study() {
System.out.println(this.getClass()+"学习 苹果电脑");
}
}
小米电脑
package factory.product;
public class MiComputer implements Computer {
@Override
public void play() {
System.out.println(this.getClass()+"玩 小米电脑");
}
@Override
public void study() {
System.out.println(this.getClass()+"学习 小米电脑");
}
}
手机接口
package factory.product;
/**
* @Author: WYF
* @Description: 手机接口
* @Create: 2020-04-06 15:48
* @Version: 1.0
*/
public interface Phone {
/**
* @Description: 手机功能,用来玩
* @Param: []
* @Return: void
* @Author: WYF
* @Date: 2020/4/6 15:49
*/
void play();
/**
* @Description: 手机功能,打电话
* @Param: []
* @Return: void
* @Author: WYF
* @Date: 2020/4/6 15:49
*/
void call();
}
苹果手机
package factory.product;
public class IPhone implements Phone{
@Override
public void play() {
System.out.println(this.getClass()+"玩 苹果手机");
}
@Override
public void call() {
System.out.println(this.getClass()+"打电话 苹果手机");
}
}
小米手机
package factory.product;
public class MiPhone implements Phone{
@Override
public void play() {
System.out.println(this.getClass()+"玩 小米手机");
}
@Override
public void call() {
System.out.println(this.getClass()+"打电话 米手机");
}
}
测试类
package factory;
import factory.factory.*;
/**
* @Author: WYF
* @Description: 抽象工厂模式的测试
* @Create: 2020/4/6 16:13
* @Version: 1.0
*/
public class TestFactory {
public static void main(String[] args) {
Factory factory1 = new MiFactory();
Factory factory2 = new IFactory();
factory1.createComputer().play();
factory2.createPhone().call();
}
}
https://www.cnblogs.com/yssjun/p/11102162.html
工厂模式总结:
三个工厂模式,各有千秋
从简单工厂模式——》工厂方法模式,解决了对产品的拓展不符合OCT原则的问题
从工厂方法模式——》抽象工厂模式,解决了一个过程只能生产一个产品的问题
但是反而多了一个问题,就是又产生了部分不符合OCT原则的问题,对工厂的拓展符合OCT,但是没错要拓展一个产品,就要修改一次工厂里面的方法
单例模式
单例模式核心:
提供唯一实例
构造方法私有化
对外提供静态方法
懒汉式与饿汉式
饿汉式没有线程安全问题,懒汉式就有
饿汉式优化
使用静态代码块,比起直接就new,它可以实现更复杂的功能,比如读取配置文件
package single;
import java.io.IOException;
import java.util.Properties;
/**
* @Author: WYF
* @Description: 饿汉单例,用静态代码块饿汉式,
* 比起直接就new,它可以实现更复杂的功能,比如读取配置文件
* @Create: 2020/3/30 15:28
* @Version: 1.0
*/
public class SingleTon2 {
public static final SingleTon2 INSTANCE;
private String info;
static {
try {
Properties properties = new Properties();
properties.load(SingleTon2.class.getClassLoader().getResourceAsStream("singleton.properties"));
INSTANCE = new SingleTon2(properties.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException();
}
}
private SingleTon2(String info){
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "SingleTon2{" +
"info='" + info + '\'' +
'}';
}
}
解决懒汉式的线程安全问题
1.双端锁+volatile
package single;
/**
* @Author: WYF
* @Description: 双端锁+volatile实现懒汉的单例
* @Create: 2020/3/30 15:25
* @Version: 1.0
*/
public class SingleTon {
volatile private static SingleTon singleTon = null;
private SingleTon(){
System.out.println("实例化1次");
}
public static SingleTon getInstance(){
/**
*
*/
if (singleTon == null){
synchronized (SingleTon.class){
if (singleTon == null) {
singleTon = new SingleTon();
}
}
}
return singleTon;
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(() -> {
SingleTon.getInstance();
}, String.valueOf(i)).start();
}
}
}
拓展问题:为什么要锁两次?
解释:当A与B同时调用getSingleton时,判断第一个if都为空,这时A拿到锁,进行第二层if判断,条件成立new了一个对象;
B在外层等待,A创建完成,释放锁,B拿到锁,进行第二层if判断,条件不成立,结束释放锁。C调用getSingleton时第一层判断不成立,直接拿到singleton对象返回,避免进入锁,减少性能开销。
————————————————
版权声明:本文为CSDN博主「小韩同志」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jlnu0812407/article/details/102836187
volatile的作用?
https://www.cnblogs.com/dolphin0520/p/3920373.html
2.静态内部类的方法(属于懒汉的一种)
package single;
/**
* @Author: WYF
* @Description: SingleT的最佳,用静态内部类实现
* 在内部类被加载/初始化的时候创建对象,
* 静态内部类不不会随着外部类的初始化而初始化
* @Create: 2020/3/30 15:50
* @Version: 1.0
*/
public class SingleTon3 {
/**
* 第一步,毫无疑问,构造器私有
*/
private SingleTon3(){};
/**
* 2.静态内部类
*/
private static class SingletonHolder{
private static final SingleTon3 INSTANCE = new SingleTon3();
}
/**
* @Description: d
* @Param:
* @Return:
* @Author: WYF
* @Date: 2020/3/30 15:54
*/
public static final SingleTon3 getInstance(){
return SingletonHolder.INSTANCE;
}
}
静态内部类的特性,实例并不是在该类被加载的时候创建的,而是当getInstance()方法被调用的时候。所以解决了资源浪费的问题。
https://www.cnblogs.com/maohuidong/p/7843807.html
拓展:静态内部类的初始化时间
虽然静态内部类需要外部类存在的时候才能存在,但仅仅初始化外部类,不会对静态内部类初始化(这里的初始化指代类的初始化)
最好用的枚举方式
package single;
/**
* @Author: WYF
* @Description:枚举实现单例设计模式
* @Create: 2020/3/30 23:00
* @Version: 1.0
*/
public enum EasySingleton{
INSTANCE;
}
/**
* 更重要的是枚举不会存在反射问题(其他版本可以通过破坏构造器的私有化),jdk对枚举是序列化实现了特殊的规定
*/
为什么这个最好?
1.写法方便
2.底层封装了这种实现,安全
底层如何实现线程安全?
1.枚举默认构造方法私有化
2.用JVM底层来实现唯一实例
反编译可以看到,他使用了static关键字来实例化:
jvm对类的加载解析初始化只有一次,并在初始化这里走静态代码块,我用到枚举他才初始化我要的对象。
详细:
了解JVM的类加载机制的朋友应该对这部分比较清楚。static类型的属性会在类被加载之后被初始化,当一个Java类第一次被真正使用到的时候静态资源会被初始化、Java类的加载和初始化过程都是线程安全的(因为虚拟机在加载枚举的类的时候,会使用ClassLoader的loadClass方法,而这个方法使用同步代码块保证了线程安全)。所以,创建一个enum类型是线程安全的。
也就是说,我们定义的一个枚举,在第一次被真正用到的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的。而我们知道,解决单例的并发问题,主要解决的就是初始化过程中的线程安全问题。
所以,由于枚举的以上特性,枚举实现的单例是天生线程安全的。
————————————————
版权声明:本文为CSDN博主「CrankZ」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/CrankZ/article/details/84954388
结构型模式
组合模式
用来干什么的?
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
分析:
1.最根本的节点,我们称呼他为叶子(leaf)
2.在组合叶子的物体,我们称呼他为合成部件(Composite)
3.我们的目的是让leaf和Composite具有一致性,我们就可以“盲目”地以一种相同的方式操作这个整体。
4.抽取出,组合对象操作的统一接口Component
5.两种模式
5.1 透明方式:在接口里加入default方法或者把方法改为接口,在Component中声明所有来管理子对象的方法,其中包括Add,Remove等。这样实现Component接口的所有子类都具备了Add和Remove方法。这样做的好处是叶节点和枝节点对于外界没有区别,它们具备完全一致的接口。
5.2 安全方式:在Component中不去声明Add和Remove方法,那么子类的Leaf就不需要实现它,而是在Composit声明所有用来管理子类对象的方法。
5.3 两种方式有缺点:对于透明方式,客户端对叶节点和枝节点是一致的,但叶节点并不具备Add和Remove的功能,因而对它们的实现是没有意义的;对于安全方式,叶节点无需在实现Add与Remove这样的方法,但是对于客户端来说,必须对叶节点和枝节点进行判定,为客户端的使用带来不便。
自己的理解:透明模式的好处在于调用add/remove方法不需要转成component;而我用安全模式时候,每次都是去执行component的方法,接口里没有具体实现
https://blog.csdn.net/weixin_34242819/article/details/89987637
https://blog.csdn.net/weixin_34242819/article/details/89987637
安全模式的代码:
package Component;
/**
* @Author: WYF
* @Description: 组合对象操作的统一接口
* @Create: 2020-04-21 02:01
* @Version: 1.0
*/
public interface Component {
void doSomething();
}
package Component;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: WYF
* @Description: 在组合叶子的物体,组合部件
* @Create: 2020/4/21 2:05
* @Version: 1.0
*/
public class Composite implements Component{
private List<Component> list = new ArrayList<Component>();
public void add(Component component) {
list.add(component);
}
public void remove(Component component) {
list.remove(component);
}
public List<Component> getAll() {
return list;
}
@Override
public void doSomething() {
for (Component component : list) {
component.doSomething();
}
}
}
package Component;
/**
* @Author: WYF
* @Description: 叶子节点
* @Create: 2020/4/21 1:57
* @Version: 1.0
*/
public class Leaf implements Component{
@Override
public void doSomething() {
System.out.println("dosomething");
}
}
package Component;
/**
* @Author: WYF
* @Description: 测试类
* @Create: 2020/4/21 2:06
* @Version: 1.0
*/
public class TestComponent {
public static void main(String[] args) {
Component leaf1 = new Leaf();
Component leaf2 = new Leaf();
Composite composite = new Composite();
composite.add(leaf1);
composite.add(leaf2);
Composite composite2 = new Composite();
Component leaf3 = new Leaf();
composite2.add(composite);
composite2.add(leaf3);
composite2.doSomething();
}
}
Junit是什么
Java的Junit——Java语言的单元测试框架
一、简单描述一下安装过程——>
1.idea里面插件JUnitGenerator V2.0
2.在maven里面引入依赖
3.写一个测试类,在需要测试的方法上加一个@Test注解
4.执行测试
二、主要事项——>
1、每一个测试方法上使用@Test进行修饰
2、每一个测试方法必须使用public void 进行修饰
3、每一个测试方法不能携带参数
4、测试代码和源代码在两个不同的项目路径下
三、体会
1.以前的测试代码过程:
在main 方法里面写。
对多个方法调用。
需要添加打印或者输出语句。
添加了新的测试方法。
需要在main方法添加方法调用。
不能形成整体的测试结果。
需要对打印或者输出结果进行人为的判断。
2.用了Junit之后:
- 可以书写一系列的 测试方法,对项目所有的 接口或者方法进行单元测试。
2.启动后,自动化测试,并判断执行结果, 不需要人为的干预。
3.只需要查看最后结果,就知道整个项目的方法接口是否通畅。
4.每个单元测试用例相对独立, 由Junit 启动,自动调用。 不需要添加额外的调用语句。
5.添加,删除,屏蔽测试方法,不影响其他的测试方法。 开源框架都对JUnit 有相应的支持。
junit3中引入组合模式的好处
1)简化了JUnit的代码 JUnit可以统一处理组合结构TestSuite和单个对象TestCase。使JUnit开发变得简单容易,因为不需要区分部分和整体的区别,不需要写一些充斥着if else的选择语句;
2)定义了TestCase对象和TestSuite的类层次结构基本对象TestCase可以被组合成更复杂的组合对象TestSuite,而这些组合对象又可以被组合,如上个例子,这样不断地递归下去。在程序的代码中,任何使用基本对象的地方都可方便的使用组合对象,大大简化系统维护和开发;
3)使得更容易增加新的类型的TestCase;
自己的理解:方便管理,对维护开发很好用
http://blog.sina.com.cn/s/blog_6cf812be0100wbhq.html
适配器模式
产生:
解决兼容性问题,让两个没有关系的类/接口一起工作
package adapter;
/**
* @Author: WYF
* @Description: 适配器接口
* @Create: 2020-04-13 15:27
* @Version: 1.0
*/
public interface Target {
/**
* @Description: 需要适配被别人的方法
* @Param: []
* @Return: void
* @Author: WYF
* @Date: 2020/4/13 15:32
*/
void request();
}
package adapter;
/**
* @Author: WYF
* @Description: 被适配的对象
* @Create: 2020/4/13 15:36
* @Version: 1.0
*/
public class Adaptee {
public void adapteeRequest(){
System.out.println("被适配的方法");
}
}
package adapter.twomethod;
import adapter.Adaptee;
import adapter.Target;
/**
* @Author: WYF
* @Description: 我们的需求就是要Target的接口实现Adaptee的方法
* 第一种是类适配模式,从类继承的角度,实现适配器
* @Create: 2020/4/13 15:39
* @Version: 1.0
*/
public class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
System.out.println("request本身的方法");
super.adapteeRequest();
}
}
package adapter.twomethod;
import adapter.Adaptee;
import adapter.Target;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: WYF
* @Description: 组合的方式,实现适配
* @Create: 2020/4/13 16:34
* @Version: 1.0
*/
public class ObjectAdapter implements Target {
Adaptee a = new Adaptee();
@Override
public void request() {
a.adapteeRequest();
System.out.println("request的方法");
}
}
MVC架构的实现
https://blog.csdn.net/wwwdc1012/article/details/82780560
[外链
注意 上面的controller只是表示一个业务处理,应该说是适配器去适配具体的对象,执行对应的controller
也可能不代表就是一个实实在在的controller,他有可能调用多个controller
上图是DispatcherServlet的结构,
那他又是如何工作的呢?
从结构中我们可以看到:
1.适配器模式我们将所有写好的 controller
统一交给 具体实现类,比如HttpRequestHandlerAdapter
处理
2.所有的HandlerAdapter实现类都继承了HandlerAdapter接口
3.把所有的接口放入DispatcherServlet中
实际工作的时候,我们在看这张图
可以看出,
1.每当客户端发送一个请求,先通过前端映射器,然后去HanderMapping找到对应的Handler(Handler可以简单理解为一个请求)
(对应123)
2.知道了我的Handler,我们就通过适配器的模式是在这部分体现的。
根据handler得到对应的适配器
通过适配器去调用对应controller的方法,并返回ModelAndView
(对应4567)
3.剩下的就是
往视图解析器传入ModelAndView
返回解析后的数据渲染视图的工作啦
好处:
免去了写大量的 if-else
语句对 Controller
进行判断,也更利于扩展新的 Controller
类型。
桥接模式
桥接模式:
定义 :将抽象部分与它的实现部分分离,使它们都可以独立地变化。
意图 :将抽象与实现解耦。
桥接模式所涉及的角色
\1. Abstraction :定义抽象接口,拥有一个Implementor类型的对象引用
\2. RefinedAbstraction :扩展Abstraction中的接口定义
\3. Implementor :是具体实现的接口,Implementor和RefinedAbstraction接口并不一定完全一致,实际上这两个接口可以完全不一样Implementor提供具体操作方法,而Abstraction提供更高层次的调用
\4. ConcreteImplementor :实现Implementor接口,给出具体实现
Jdk中的桥接模式:JDBC
JDBC连接 数据库 的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不动,原因就是JDBC提供了统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了
代理模式
定义
代理对象把责任委托给了真实对象去处理
代理与反射的关系?
反射只是代理的一种实现,除了反射还有
动态代理与静态代理的区别
静态代理:
eg:新编写一个对象,在对象里面依赖被代理的对象
https://www.jianshu.com/p/9bcac608c714
不足:需要编写很多类实现代理
动态代理:
在运行时候创建代理对象,两种实现方式,更加灵活
动态代理!=反射
两种实现方式中 CGLib是通过字节码操作框架实现
Lombok
它也是一种动态代理,但是没有用到方式,而是编译的时候解析
Spring
bean的实例化过程就用到,默认是用proxy,如果没有就接口,再使用CGLib
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyExample{
static interface Car{
void running();
}
static class Bus implements Car{
@Override
public void running() {
System.out.println("The bus is running");
}
}
static class Taxi implements Car{
@Override
public void running() {
System.out.println("The Taxi is running");
}
}
static class JDKProxy implements InvocationHandler{
/**
* @Description: 代理对象
*/
private Object target;
/**
* 取得代理对象(此时的代理对象已经委托完毕)
*/
public Object getInstance(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* @Description: 执行代理的方法
* @Param: proxy:代理对象
* @Param: method:代理方法
* @Param: args:参数
* @Return: java.lang.Object
* @Author: WYF
* @Date: 2020/4/7 11:20
*/
@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) {
JDKProxy jdkProxy = new JDKProxy();
Car instance = (Car) jdkProxy.getInstance(new Taxi());
instance.running();
}
}
CGLib 字节码操作框架的
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibExample{
static class Bus {
public void running() {
System.out.println("The bus is running");
}
}
static class CGLibProxy implements MethodInterceptor{
/**
* @Description: 代理对象
*/
private Object target;
/**
* 取得代理对象(此时的代理对象已经委托完毕)
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("qian");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("hou");
return invoke;
}
}
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
Bus instance = (Bus) proxy.getInstance(new Bus());
instance.running();
}
}
行为型模式
命令模式
具体做什么不确定,只有在执行的时候才确定
客户端
package command;
/**
* @Author: WYF
* @Description: 测试类
* @Create: 2020/3/30 17:45
* @Version: 1.0
*/
public class CommendTest {
public static void main(String[] args) {
ProcessArray processArray = new ProcessArray();
int[] arr = {3,4,5,6,7};
processArray.process(arr, (int[] target) ->{
for (int a:
target) {
System.out.println(a);
}
System.out.println("哈哈哈哈哈哈");
});
System.out.println("--------");
processArray.process(arr, c2);
}
}
命令(演示的demo没有接收者,即 命令执行不要接受参数)
package command;
/**
* @Author: WYF
* @Description: 接口 封装处理行为
* @Create: 2020-03-30 17:36
* @Version: 1.0
*/
@FunctionalInterface
public interface Command {
/**
* 抽象方法
*
* @Param targer 数组,要处理的
* @Return void
*/
void process(int[] targer);
}
具体命令1
package command;
/**
* @Author: WYF
* @Description: 实现command接口的连续打印
* @Create: 2020/3/30 17:53
* @Version: 1.0
*/
public class PrintfCommend implements Command{
@Override
public void process(int[] targer) {
for (int a:targer) {
System.out.print(a + "\t ");
}
System.out.println("");
}
}
具体命令2
package command;
/**
* @Author: WYF
* @Description: 实现command接口的连续加
* @Create: 2020/3/30 17:53
* @Version: 1.0
*/
public class AddCommend implements Command {
@Override
public void process(int[] targer) {
int sum = 0;
for (int i = 0; i < targer.length; i++) {
sum += targer[i];
}
System.out.println(sum);
}
}
请求者
package command;
/**
* @Author: WYF
* @Description: 命令模式
* @Create: 2020/3/30 17:44
* @Version: 1.0
*/
public class ProcessArray {
/**
* @Description: 对数组处理,什么处理方式不确定
* @Param: [targer, command]
* @Return: void
* @Author: WYF
* @Date: 2020/3/30 17:45
*/
public void process(int[] targer,Command command){
command.process(targer);
}
}
好处:
1.拓展性好,可移植性好,
接受不同命令,调用不同方法
2.在面向对象的系统开发中,可以作为一种回调函数的作用
一开始只是先登记着,可能是一个空指针,当我真正用这个函数的时候,再设置他的实现函数,这样就很灵活,可以实现复用