黑马程序员——javase进阶——day12——网络编程

目录:

  1. 网络编程
    1. 软件架构
    2. 什么是网络编程
    3. 网络编程三要素
    4. IP地址
    5. 端口
    6. 通信协议
  2. TCP通信
    1. TCP发送数据
    2. TCP接收数据
    3. TCP通信原理分析
    4. TCP三次握手
    5. TCP练习1
    6. TCP练习2
    7. TCP练习3
  3. Junit单元测试
    1. Junit4单元测试概述
    2. Junit的基本使用
    3. 断言
  4. 单例设计模式
    1. 学习目标
    2. 内容讲解
    3. 单例设计模式的作用
    4. 单例设计模式实现步骤
    5. 单例设计模式的类型
    6. 饿汉单例设计模式
    7. 懒汉单例设计模式
    8. 知识小结
  5. 多例设计模式
    1. 学习目标
    2. 内容讲解
    3. 多例设计模式的作用
    4. 实现步骤
    5. 实现代码
    6. 小结
  6. 工厂设计模式
    1. 学习目标
    2. 内容讲解
    3. 概述
    4. 作用
    5. 案例实践
    6. 实现代码
    7. 知识小结

1.网络编程

软件架构
  • C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件

  • B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等

  • 两种架构各有优势,但是都离不开网络的支持。网络编程 , 就是在一定的协议下,实现两台计算机的通信的程序

什么是网络编程
  • 在网络通信协议下,不同计算机上运行的程序,可以进行数据传输

网络编程三要素
  • IP地址 : 设备在网络中的地址,是唯一的标识。

  • 端口 : 设备在网络中的地址,是唯一的标识。

  • 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。

IP地址
  • IP:全称”互联网协议地址”,也称IP地址。是分配给上网设备的数字标签。常见的IP分类为:ipv4和ipv6

    简单来说 : 就是设备在网络中的唯一标识 , 想要连接哪一台电脑 , 就找到此电脑在网络中的ip地址

  • IP地址常见分类 : ipv4和ipv6

  • 常用命令:

    • ipconfig:查看本机IP地址

    • IP地址:检查网络是否连通

  • 特殊IP地址:

    • 127.0.0.1:是回送地址也称本地回环地址,可以代表本机的IP地址,一般用来测试使用

  • 为了方便我们对IP地址的获取和操作,Java提供了一个类InetAddress 供我们使用 InetAddress:此类表示Internet协议(IP)地址

static InetAddress getByName(String host)在给定主机名的情况下确定主机的 IP 地址
String getHostName()获取此 IP 地址的主机名
String getHostAddress()返回 IP 地址字符串(以文本表现形式)。
端口
  • 端口:应用程序在设备中唯一的标识。

  • 端口号:应用程序的唯一标识方式 , 用两个字节表示的整数,它的取值范围是0~65535。 其中0~1023之间的端口号用于一些知名的网络服务或者应用。 我们自己使用1024以上的端口号就可以了。

  • 注意:一个端口号只能被一个应用程序使用。

通信协议
  • 协议:计算机网络中,连接和通信的规则被称为网络通信协议

  • UDP协议

    • 用户数据报协议(User Datagram Protocol)

    • UDP是面向无连接通信协议。

    • 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据。

  • TCP协议

    • 传输控制协议 (Transmission Control Protocol)

    • TCP协议是面向连接的通信协议。

    • 速度慢,没有大小限制,数据安全

2.TCP通信

TCP发送数据
package com.itheima.tcp_demo.demo1;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

/*
    客户端 :

    发送数据的步骤
        1 创建客户端的Socket对象 : Socket(String host, int port) 与指定服务端连接
            参数说明:
            host 表示服务器端的主机名,也可以是服务器端的IP地址,只不过是String类型的
            port 表示服务器端的端口

        2 通获Socket对象取网络中的输出流,写数据
            OutputStream getOutputStream()

        3 释放资源
            void close()

 */
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端的Socket对象(Socket) 与指定服务端连接
        Socket socket = new Socket("127.0.0.1", 10010);

        // 通获Socket对象取网络中的输出流,写数据
        OutputStream os = socket.getOutputStream();
        os.write("hello".getBytes());

        // while(true){}

        // 释放资源
        os.close();
        socket.close();
    }
}
TCP接收数据
package com.itheima.tcp_demo.demo1;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/*
     服务端接收数据 :

    1 创建服务器端的Socket对象 : ServerSocket类
        ServerSocket(int port)  : 构造方法需要绑定一个端口号 , port就是端口号

    2 监听客户端连接,并接受连接,返回一个Socket对象
        Socket accept() : 该方法会一直阻塞直到建立连接

    3 获取网络中的输入流,用来读取客户端发送过来的数据
        InputStream getInputStream()

    4 释放资源 : 服务端一般不会关闭
        void close()
 */
public class ServerDemo {
    public static void main(String[] args) throws IOException {
//        1 创建服务器端的Socket对象 : ServerSocket类
//        ServerSocket(int port)  : 构造方法需要绑定一个端口号 , port就是端口号
        ServerSocket serverSocket = new ServerSocket(10010);

//        2 监听客户端连接,并接受连接,返回一个Socket对象
//        Socket accept() : 该方法会一直阻塞直到建立连接
        Socket socket = serverSocket.accept();
//
//        3 获取网络中的输入流,用来读取客户端发送过来的数据
//        InputStream getInputStream()
        InputStream is = socket.getInputStream();
        int by;
        System.out.println("read方法执行前");
        while ((by = is.read()) != -1) {
            System.out.print((char) by);
        }
        System.out.println("read方法执行后");
    }
}
TCP通信原理分析

TCP三次握手
TCP练习1
package com.itheima.tcp_demo.test1;

import java.io.*;
import java.net.Socket;

/*
    客户端 :

    发送数据的步骤
        1 创建客户端的Socket对象 : Socket(String host, int port) 与指定服务端连接
            参数说明:
            host 表示服务器端的主机名,也可以是服务器端的IP地址,只不过是String类型的
            port 表示服务器端的端口

        2 通获Socket对象取网络中的输出流,写数据
            OutputStream getOutputStream​()

        3 释放资源
            void close​()

 */
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端的Socket对象(Socket) 与指定服务端连接
        Socket socket = new Socket("127.0.0.1", 10010);

        // 通获Socket对象取网络中的输出流,写数据
        OutputStream os = socket.getOutputStream();
        os.write("hello".getBytes());
        // 像服务端写入结束标记
        socket.shutdownOutput();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = br.readLine();
        System.out.println(line);

        // 释放资源
        br.close();
        os.close();
        socket.close();
    }
}
package com.itheima.tcp_demo.test1;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/*
     服务端接收数据 :

    1 创建服务器端的Socket对象 : ServerSocket类
        ServerSocket​(int port)  : 构造方法需要绑定一个端口号 , port就是端口号

    2 监听客户端连接,并接受连接,返回一个Socket对象
        Socket accept​() : 该方法会一直阻塞直到建立连接

    3 获取网络中的输入流,用来读取客户端发送过来的数据
        InputStream getInputStream​()

    4 释放资源 : 服务端一般不会关闭
        void close​()
 */
public class ServerDemo {
    public static void main(String[] args) throws IOException {
//        1 创建服务器端的Socket对象 : ServerSocket类
//        ServerSocket​(int port)  : 构造方法需要绑定一个端口号 , port就是端口号
        ServerSocket serverSocket = new ServerSocket(10010);

//        2 监听客户端连接,并接受连接,返回一个Socket对象
//        Socket accept​() : 该方法会一直阻塞直到建立连接
        Socket socket = serverSocket.accept();
//
//        3 获取网络中的输入流,用来读取客户端发送过来的数据
//        InputStream getInputStream​()
        InputStream is = socket.getInputStream();
        int by;

        while ((by = is.read()) != -1) {
            System.out.print((char) by);
        }

        BufferedWriter bos = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bos.write("你谁啊");

        bos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}
TCP练习2
package com.itheima.tcp_demo.test2;

import java.io.*;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象
        Socket socket = new Socket("127.0.0.1", 10086);

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg"));

        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        int by;
        while ((by = bis.read()) != -1) {// 从本地中读一个字节
            bos.write(by);// 往服务器写一个字节
            bos.flush();
        }
        // 写结束标记
        socket.shutdownOutput();

        // 把网络中的字节输入流 , 封装成高效的字符输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//        String line;
//        while ((line = br.readLine()) != null) {
//            System.out.println(line);
//        }
        String msg = br.readLine();// 读到换行才叫读到一行, 所以必须写服务器必须写newLine
        System.out.println(msg);

        // 释放资源
        bis.close();
        socket.close();
    }
}
package com.itheima.tcp_demo.test2;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务端的连接对象
        ServerSocket serverSocket = new ServerSocket(10086);
        Socket socket = null;
        BufferedInputStream bis = null;
        BufferedWriter socketBw = null;

        while (true) {
            // 获取Socket对象
            socket = serverSocket.accept();

            // 获取网络中的字节输入流  在封装成高效的字节输入流对象
            bis = new BufferedInputStream(socket.getInputStream());

            // 创建本地的字节输出流 , 封装成高效的字节输出流
            BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("day13_demo\\图片\\a.jpg"));

            int by;
            while ((by = bis.read()) != -1) {
                bw.write(by);
                bw.flush();
            }

            //关闭本地流
            bw.close();

            // 获取网络中的字节输出流 , 封装成高效的字符输出流
            socketBw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            socketBw.write("谢谢你");
            socketBw.newLine();// 必须有换行 , 因为readLine读到换行结束
            socketBw.flush();
        }

        // 释放资源
//        socketBw.close();
//        bis.close();
//        socket.close();
//        serverSocket.close();
    }
}
TCP练习3
package com.itheima.tcp_demo.test3;

import java.io.*;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象
        Socket socket = new Socket("127.0.0.1", 10086);

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg"));

        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        int by;
        while ((by = bis.read()) != -1) {// 从本地中读一个字节
            bos.write(by);// 往服务器写一个字节
            bos.flush();
        }
        // 写结束标记
        socket.shutdownOutput();

        // 把网络中的字节输入流 , 封装成高效的字符输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//        String line;
//        while ((line = br.readLine()) != null) {
//            System.out.println(line);
//        }
        String msg = br.readLine();// 读到换行才叫读到一行, 所以必须写服务器必须写newLine
        System.out.println(msg);

        // 释放资源
        bis.close();
        socket.close();
    }
}
package com.itheima.tcp_demo.test3;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务端的连接对象
        ServerSocket serverSocket = new ServerSocket(10086);

        ExecutorService executorService = Executors.newFixedThreadPool(10);
        while (true) {
            // 获取Socket对象
            Socket socket = serverSocket.accept();
            executorService.submit(new ServerThread(socket));
        }

        // 释放资源
//        socketBw.close();
//        bis.close();
//        socket.close();
//        serverSocket.close();
    }
}
package com.itheima.tcp_demo.test3;

import javax.management.relation.RoleUnresolved;
import java.io.*;
import java.net.Socket;
import java.util.UUID;

public class ServerThread implements Runnable {
    Socket socket = null;
    BufferedOutputStream bw = null;

    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {

        try {
            // 获取网络中的字节输入流  在封装成高效的字节输入流对象
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());

            // 创建本地的字节输出流 , 封装成高效的字节输出流
            bw = new BufferedOutputStream(new FileOutputStream("day13_demo\\图片\\" + UUID.randomUUID() + ".jpg"));

            int by;
            while ((by = bis.read()) != -1) {
                bw.write(by);
                bw.flush();
            }
            // 获取网络中的字节输出流 , 封装成高效的字符输出流
            BufferedWriter socketBw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            socketBw.write("谢谢你");
            socketBw.newLine();// 必须有换行 , 因为readLine读到换行结束
            socketBw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭本地流
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.Junit单元测试

Junit4单元测试概述
  • 单元测试就是编写测试代码,可以准确、快速地保证程序的正确性,Junit是Java单元测试的框架。

  • JUnit4可以通过注解的方式来标记方法 , 让方法存某种意义 ,常见的注解有:

    • @BeforeClass 全局只会执行一次,而且是第一个运行(标记的方法需要是一个静态无参无返回值方法)

    • @Before 在测试方法运行之前运行(非静态无参无返回值方法)

    • @Test 测试方法(此方法必须是非静态无参无返回值方法), 主要用于测试的方法

    • @After 在测试方法运行之后运行(非静态无参无返回值方法)

    • @AfterClass 全局只会执行一次,而且是最后一个运行(标记的方法需要是一个静态无参无返回值方法)

    • @Ignore 忽略此方法

Junit的基本使用
  • 已知存在需要测试的类Calculator ,这是一个能够简单实现加减乘除、平方、开方的计算器类,然后对这些功能进行单元测试。

// 计算器类
public class Calculator {
    // 静态变量,用于存储运行结果
    private static int result; // 20
  
    // 加法运算
    public void add(int n) {
        result = result + n;
    }
    
    // 减法运算
    public void subtract(int n) {
        // Bug: 正确的应该是 result = result - n
        result = result - 1;  
    }
  
    // 乘法运算
    public void multiply(int n) {
        // 此方法尚未写好
    }         
  
    // 除法运算
    public void divide(int n) {
        result = result / n;
    }
    
    // 平方运算
    public void square(int n) {
        result = n * n;
    }
    
    // 平方根运算
    public void squareRoot(int n) {
        // Bug : 死循环
        for (; ;) ;            
    }
    
    // 将结果清零
    public void clear() {     
        result = 0;
    }
    
    // 返回运算结果
    public int getResult(){
        return result;
    }
}
  • 引入Junit4的jar包到模块中

    • 第一步 : 在模块中新建文件夹lib,拷贝今天资料中junit4的jar包到模块中

    • 第二步 : 选中jar文件 , 右键选择 Add as Library

  • 生成Junit测试框架

    • 使用IDEA能够直接给需要测试的类生成测试框架,如下:

    • 选中本类任何位置右键选择 Generate(Alt+Insert)/ go to 选项 , 选择Test...

  • 选择需要进行测试的方法

在上一步OK后系统会自动生成一个新类CalculatorTest,里面包含一些空的测试用例。你只需要将这些测试用例稍作修改即可使用,完整的CalculatorTest代码如下:

限时测试

对于那些逻辑很复杂,循环嵌套比较深的程序,很有可能出现死循环,因此一定要采取一些预防措施。限时测试是一个很好的解决方案。我们给这些测试函数设定一个执行时间,超过了这个时间,他们就会被系统强行终止,并且系统还会向你汇报该函数结束的原因是因为超时,这样你就可以发现这些Bug了。要实现这一功能,只需要给@Test标注加一个参数即可,代码如下:

被测方法

public void squareRoot(int n) {
    //Bug : 死循环
    for (; ; ) ;            
}

测试方法:

@Test(timeout = 1000)
// Timeout参数表明了你要设定的时间,单位为毫秒,因此1000就代表1秒。
public void squareRoot() {
    calculator.squareRoot(4);
    assertEquals(2 , calculator.getResult());
}
断言
  • 概述 :

预先判断某个条件一定成立,如果条件不成立,则直接报错。

  • 使用 :

//第一个参数表示期望值
//第二个参数表示实际值
// 如果实际值和期望值相同,说明结果正确就测试通过,如果不相同,说明结果是错误的,就会报错
Assert.assertEquals( 期望值, 实际值);
Assert.assertEquals("异常原因", 期望值, 实际值);

//例如:
int result = add(100,200);
Assert.assertEquals(300, result);  
  • 小结 : 如何进行断言
Assert.assertEquals(期望值,实际值)

4.单例设计模式

学习目标
  • 能够使用单例设计模式设计代码

内容讲解
  • 正常情况下一个类可以创建多个对象

public static void main(String[] args) {
	// 正常情况下一个类可以创建多个对象
	Person p1 = new Person();
	Person p2 = new Person();
	Person p3 = new Person();
}
  •  如果说有时一个对象就能搞定的事情 , 非要创建多个对象 , 浪费内存!!!
单例设计模式的作用
  • 单例模式,是一种常用的软件设计模式。通过单例模式可以保证项目中,应用该模式的这个类只有一个实例。

    即一个类只有一个对象实例。

  • 好处 :可以节省内存,共享数据

单例设计模式实现步骤
  1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

  2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static 类型的成员变量。

  3. 定义一个静态方法返回这个唯一对象。

单例设计模式的类型

根据创建对象的时机单例设计模式又分为以下两种:

  1. 饿汉单例设计模式

  2. 懒汉单例设计模式

饿汉单例设计模式
  • 饿汉单例设计模式就是使用类的时候已经将对象创建完毕

    不管以后会不会使用到该实例化对象,先创建了再说。很着急的样子,故被称为“饿汉模式”。

  • 代码如下:

public class Singleton {
    // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Singleton() {}

    // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static 类型的成员变量。
    private static final Singleton instance = new Singleton();
    
    // 3.定义一个静态方法返回这个唯一对象。
    public static Singleton getInstance() {
        return instance;
    }
}
  • 需求:定义一个皇帝类,要求对象只能存在一个。
package com.itheima.singledesign;
/*
    需求 : 使用单例模式(饿汉式) , 要求此类只能有一个对象

    步骤 :
        1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
        2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static 类型的成员变量。
        3. 定义一个静态方法返回这个唯一对象。
 */
public class King {
    // 1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private King(){

    }

    // 2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static 类型的成员变量。
    private static final King KING = new King();

    // 3. 定义一个静态方法返回这个唯一对象。
    public static King getInstance(){
        return KING;
    }
}
懒汉单例设计模式
  • 懒汉单例设计模式就是调用getInstance()方法时对象才被创建

    也就是说先不急着实例化出对象,等要用的时候才实例化出对象。不着急,故称为“懒汉模式”。

  • 代码如下:

public class Singleton {
 
	 // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Singleton() {}
    
    // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
    private static Singleton instance;

    // 3.定义一个静态方法返回这个唯一对象。要用的时候才例化出对象

    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

注意 :

  • 懒汉单例设计模式在多线程环境下可能会实例化出多个对象,不能保证单例的状态,所以加上关键字:synchronized,保证其同步安全。

  • 需求:使用懒汉单例 ,改写皇帝类的单例模式  
package com.itheima.singledesign;

/*
    需求 : 使用单例模式(懒汉式) , 要求此类只能有一个对象

    步骤 :
        1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
        2. 在该类内部定义一个private static修饰的成员变量 . 此变量不需要赋值
        3. 定义一个静态方法返回这个唯一对象。 此方法需要加上synchronized关键字保证在多线程中也只有一个实例对象
 */
public class King2 {
    // 1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private King2() {
    }

    //  2. 在该类内部定义一个private static修饰的成员变量 . 此变量不需要赋值
    private static King2 king2;

    // 3. 定义一个静态方法返回这个唯一对象。 此方法需要加上synchronized关键字保证在多线程中也只有一个实例对象
    public static synchronized King2 getInstance() {
        if (king2 == null) {
            king2 = new King2();
        }
        return king2;
    }
}
知识小结 
  • 单例模式可以保证系统中一个类只有一个对象实例。

  • 实现单例模式的步骤:

    • 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

    • 在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。

    • 定义一个静态方法返回这个唯一对象。

5.多例设计模式

学习目标
  • 能使用多例设计模式设计代码

内容讲解
多例设计模式的作用
  • 多例模式,是一种常用的设计模式之一。通过多例模式可以保证项目中,应用该模式的类有固定数量的实例。

    多例类要自我创建并管理自己的实例,还要向外界提供获取本类实例的方法。

  • 使用场景:线程池

线程池 = Executors.newFixedThreadPool(3);
实现步骤
  1. 创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在类中定义该类被创建对象的总数量
  3. 在类中定义存放类实例的list集合
  4. 在类中提供静态代码块,在静态代码块中创建类的实例
  5. 提供获取类实例的静态方法
实现代码
  • 某一个学科有固定3位老师,年级中上该课程的老师就是这三位老师其中一位要求使用多例模式 ,每次获取的都是这三位老师其中一位

package com.itheima.moreinstance_demo;

import java.util.ArrayList;
import java.util.Random;

/*
    需求  : 某一个学科有固定3位老师,年级中上该课程的老师就是这三位老师其中一位
            要求使用多例模式 ,每次获取的都是这三位老师其中一位

    实现步骤 :
        1.创建一个类,  将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
        2.在类中定义该类被创建对象的总数量
        3.在类中定义存放类实例的list集合
        4.在类中提供静态代码块,在静态代码块中创建类的实例
        5.提供获取类实例的静态方法
 */
public class Teacher {
    // 1.创建一个类,  将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Teacher() {
    }

    // 2.在类中定义该类被创建对象的总数量
    private static int maxCount = 3;

    // 3.在类中定义存放类实例的list集合
    private static ArrayList<Teacher> list = new ArrayList<>();// {teacher1  , teacher2 , teacher3}

    // 4.在类中提供静态代码块,在静态代码块中创建类的实例
    static {
        for (int i = 0; i < maxCount; i++) {
            list.add(new Teacher());
        }
    }

    // 5.提供获取类实例的静态方法
    public static Teacher getInstance() {
        int index = new Random().nextInt(3);// [0 - 2]
        return list.get(index);
    }

}
小结
  • 多例模式作用 : 可以保证项目中一个类有固定个数的实例, 在实现需求的基础上, 能够提高实例的复用性.

    实现多例模式的步骤 :

    • 创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

    • 在类中定义该类被创建的总数量

    • 在类中定义存放类实例的list集合

    • 在类中提供静态代码块,在静态代码块中创建类的实例

    • 提供获取类实例的静态方法

6.工厂设计模式

学习目标
  • 能够使用工厂设计模式设计代码

内容讲解
概述
  • 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。之前我们创建类对象时, 都是使用 new 对象的形式创建, 除new 对象方式以外, 工厂模式也可以创建对象.
作用
  • 解决类与类之间的耦合问题
案例实践
  • 需求:定义汽车工厂类,生产各种品牌的车

  • 实现步骤

    • 编写一个Car接口, 提供run方法

    • 编写一个Falali类实现Car接口,重写run方法

    • 编写一个Benchi类实现Car接口,重写run方法

    • 提供一个CarFactory(汽车工厂),用于生产汽车对象

    • 定义CarFactoryTest测试汽车工厂

实现代码  
package com.itheima.factorydesign_demo;

/*
  - 需求:定义汽车工厂类,生产各种品牌的车

  - 实现步骤
      - 编写一个Car接口, 提供run方法
      - 编写一个Falali类实现Car接口,重写run方法
      - 编写一个Benchi类实现Car接口
      =============================================
      - 提供一个CarFactory(汽车工厂),用于生产汽车对象
      - 定义CarFactoryTest测试汽车工厂
 */
public class CarTest {
    public static void main(String[] args) {
        Car benchi = CarFactory.getInstance(Brand.BENCHI);
        System.out.println(benchi);
    }
}

// 汽车接口
interface Car {
    public abstract void run();
}

// 编写一个Falali类实现Car接口,重写run方法
class Falali implements Car {
    public Falali() {
    }

    @Override
    public void run() {
        System.out.println("法拉利破百需要3秒...");
    }
}

// 编写一个Benchi类实现Car接口
class Benchi implements Car {
    @Override
    public void run() {
        System.out.println("奔驰破百需要5秒...");
    }
}

// 汽车品牌枚举
enum Brand {
    BENCHI, FALALI, BAOMA, BINLI, AODI;
}

// 提供一个CarFactory(汽车工厂),用于生产汽车对象
class CarFactory {
    private CarFactory() {
    }

    public static Car getInstance(Brand brand) {
        switch (brand) {
            case FALALI:
                return new Falali();
            case BENCHI:
                return new Benchi();
            default:
                return null;
        }
    }
}

 提供一个CarFactory(汽车工厂),用于生产汽车对象
//class CarFactory{
//    private CarFactory(){}
//
//    public static Car getInstance(String brand) {
//        if(brand.equals("Falali")){
//            return new Falali(10);
//        }else if(brand.equals("Benchi")) {
//            return new Benchi();
//        }else {
//            return null;
//        }
//    }
//}
知识小结
  • 工厂模式的存在可以改变创建对象的方式,降低类与类之间的耦合问题.

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿瞒有我良计15

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值