设计模式学习笔记

七大原则

首先理解粒度的概念:功能的细化程度,粒度大说明区分的很细,粒度小说明功能区分不大

单一职责原则

包子工厂他就只生产包子,不生产别的

一个模块功能太多,系统稳定性减低
很多其他模块使用到它,发生一点改变,可能影响整个系统
(改一个变量,有可能影响方法)

开闭原则

开:允许可以拓展功能(提供方)

闭:修改关闭(使用方)

可以修改,但是需要再不需要改现有代码的情况下去拓展功能!
因为修改现有的代码可能会给现有的代码带来错误

(工厂模式中,简单工厂模式修改代码这种就是不对的)

里氏替换原则

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之后:

  1. 可以书写一系列的 测试方法,对项目所有的 接口或者方法进行单元测试。
    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.在面向对象的系统开发中,可以作为一种回调函数的作用

一开始只是先登记着,可能是一个空指针,当我真正用这个函数的时候,再设置他的实现函数,这样就很灵活,可以实现复用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值