设计模式
1、创建型 创建对象
2、结构型 对象的组成
3、行为型 对象的功能
创建型模式:
1、单例模式
指的是在程序运行过程中,内存中只允许一个对象存在
饿汉式
懒汉式
2、简单工厂模式
3、工厂方法模式
创建型的第一种:
单例模式:保证在内存中只存在一个对象
1、将构造方法私有化
2、在类的成员变量的位置上创建一个对象
3、提供一个公共的静态方法让外界获取到这个对象
饿汉式:类一加载,就创建对象
package com.shujia.wyh.day26.shejimoshi.danli;
public class StudentDemo {
public static void main(String[] args) {
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1==s2); //true 同一个对象
}
}
class Student {
private static Student student = new Student();
private Student(){}
public static Student getStudent(){
return student;
}
}
懒汉式:用的时候,再去创建对象,但是内存中始终只有一个对象
1、懒加载(延迟加载)
2、容易产生线程安全问题
1) 在存在多线程环境中,只允许出现一个对象的类是共享数据
2) 并且有多条语句操作着共享数据
3) 需要使用锁来解决线程安全问题
package com.shujia.wyh.day26.shejimoshi.danli;
public class TeacherDemo {
public static void main(String[] args) {
Teacher t1 = Teacher.getTeacher();
Teacher t2 = Teacher.getTeacher();
System.out.println(t1==t2);
}
}
class Teacher {
private Teacher() {
}
private static Teacher t = null;
//静态的同步方法
public synchronized static Teacher getTeacher() {
if (t == null) {
t = new Teacher();
}
return t;
}
}
简单工厂模式(静态工厂方法模式)
优点:
客户端不需要负责创建对象,从而明确了各个类的职责
缺点:
我们定义的静态工厂类负责对象的创建,如果有新的对象增加
获取某些对象的创建方式不同,就需要不断的去修改工厂类,不利于后期维护
package com.shujia.wyh.day26.shejimoshi.easyfactory;
public class AnimalDemo {
public static void main(String[] args) {
Animal dog = AnimalFactory.createAnimal("Dog");
Animal cat = AnimalFactory.createAnimal("Cat");
if(dog!=null){
dog.eat();
}
if(cat!=null){
cat.eat();
}
Animal pig = AnimalFactory.createAnimal("Pig");
if(pig!=null){
pig.eat();
}
}
}
class AnimalFactory {
//构造方法私有化,让外界无法创建该类的实例
private AnimalFactory(){}
//使用多态的形式修改
public static Animal createAnimal(String type){
if("Cat".equals(type)){
return new Cat();
}else if("Dog".equals(type)){
return new Dog();
}else {
System.out.println("该工厂不支持创建"+type+"类型的动物");
return null;
}
}
}
abstract class Animal {
public abstract void eat();
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("🐕吃🥩");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("🐱吃🐟");
}
}
工厂方法模式的优缺点:
优点:
客户端不需要负责对象的创建,从而明确各个类的职责
如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可
不影响其他的代码,后期容易维护,增强了系统的扩展性。
缺点:
需要额外的写代码,增加了工作量
package com.shujia.wyh.day26.shejimoshi.factoryFunction;
public class AnimalDemo {
public static void main(String[] args) {
//我想要只狗
DogFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.eat();
//我想要只猫
CatFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.eat();
//我想要只猪
PigFactory pigFactory = new PigFactory();
Animal pig = pigFactory.createAnimal();
pig.eat();
}
}
abstract class Animal {
public abstract void eat();
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("🐕吃🥩");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("🐱吃🐟");
}
}
class Pig extends Animal{
@Override
public void eat() {
System.out.println("🐖吃饲料");
}
}
//创建工厂接口,具体工厂类实现接口
interface Factory {
public abstract Animal createAnimal();
}
class DogFactory implements Factory{
@Override
public Animal createAnimal() {
return new Dog();
}
}
class CatFactory implements Factory{
@Override
public Animal createAnimal() {
return new Cat();
}
}
class PigFactory implements Factory{
@Override
public Animal createAnimal() {
return new Pig();
}
}
网络编程
网络通信三要素
IP地址:InetAddress 网络中设备的标识,不易记忆,可用主机名
端口号 用于标识进程的逻辑地址,不同进程的标识
传输协议 通讯的规则 常见协议:TCP,UDP
InetAddress类
获取任意主机:getByName
主机名:getHostName
主机Ip地址:getHostAddress
package com.shujia.wyh.day26.network;
import java.net.InetAddress;
public class InetAddressDemo {
public static void main(String[] args) throws Exception {
InetAddress name = InetAddress.getByName("192.168.7.42");
System.out.println(name);
//public String getHostName()获取此IP地址的主机名
String hostName = name.getHostName();
System.out.println(hostName);
//public String getHostAddress()返回文本显示中的IP地址字符串。
String address = name.getHostAddress();
System.out.println(address);
}
}
UDP协议发送数据:
1、创建发送端的Socket对象
2、创建数据,并把数据打包
3、调用Socket对象的发送方法将数据发送出去
4、释放资源,关闭Socket
package com.shujia.wyh.day26.network;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class SendDemo2 {
public static void main(String[] args) throws Exception {
//1、创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket();
//2、键盘录入数据
Scanner sc = new Scanner(System.in);
String next = sc.next();
BufferedReader br = new BufferedReader(new InputStreamReader(next));
String line = null;
while ((line=br.readLine())!=null){
if("886".equals(line)){
break;
}
//如果输入的数据不是886,将数据打包发送出去
DatagramPacket packet = new DatagramPacket(line.getBytes(), line.getBytes().length,
InetAddress.getByName("192.168.7.42"), 12345);
//调用Socket对象中发送数据包的方法
ds.send(packet);
}
//释放资源
ds.close();
}
}
UDP协议接收数据:
1、创建接收端的Socket对象
2、创建一个数据包(接收容器)、
3、调用Socket对象的接收方法接收数据
4、解析数据包,得到数据并显示在控制台上
5、释放资源,关闭Socket
注意事项:
接收端程序在绑定同一个端口的时候不能同时运行多个
package com.shujia.wyh.day26.network;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class ReceiveDemo1 {
public static void main(String[] args) throws Exception {
//1、创建接收端的Socket对象
//DatagramSocket(int port)
//构造数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket ds = new DatagramSocket(12345);
//2、创建一个数据包(接收容器)
//定义个字节数组
byte[] bytes = new byte[1024];
int length = bytes.length;
//DatagramPacket(byte[] buf, int length)
//构造一个 DatagramPacket用于接收长度的数据包 length 。
DatagramPacket datagramPacket = new DatagramPacket(bytes, length);
//3、调用Socket对象的接收方法接收数据
ds.receive(datagramPacket); //程序阻塞,直到接收到数据
String ip = datagramPacket.getAddress().getHostAddress();
String hostName = datagramPacket.getAddress().getHostName();
//4、解析数据包,得到数据并显示在控制台上
//public byte[] getData()返回数据缓冲区。
byte[] data = datagramPacket.getData();
//public int getLength()返回要发送的数据的长度或接收到的数据的长度。
int length1 = datagramPacket.getLength();
String s = new String(data, 0, length1);
System.out.println(ip + ":" + hostName + "发送的数据为:" + s);
//释放资源,关闭Socket
ds.close();
}
}
TCP协议客户端代码实现:
1、创建客户端的Socket对象
这一步如果成功创建对象,就说明连接已经建立成功
2、获取输出流对象,向服务器写数据
3、释放资源,关闭Socket服务
注意事项:
要先启动服务器端,再启动客户端,否则会报连接被拒绝异常
package com.shujia.wyh.day26.network;
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo3 {
public static void main(String[] args) throws Exception {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建客户端Socket对象
Socket s = new Socket("192.168.7.42", 12345);
System.out.println("请输入想要发送的数据:");
//获取通道中字节输出流对象
OutputStream os = s.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
while (true){
String next = sc.next();
if("886".equals(next)){
s.shutdownOutput();
break;
}
bw.write(next);
bw.newLine();
bw.flush();
}
s.close();
}
}
TCP协议编写服务器端代码:
1、创建服务器端Socket对象(ServerSocket)
2、调用accept()方法,监听客户端的连接,返回一个对应客户端连接的Socket对象
3、获取通道中的输入流对象,读取客户端发送的数据,并显示在控制台上
4、释放资源,关闭Socket服务
package com.shujia.wyh.day26.network;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ServerDemo3 {
public static void main(String[] args) throws Exception {
System.out.println("================服务器启动=======================");
//创建服务器端自身的Socket对象
ServerSocket ss = new ServerSocket(12345);
//监听的时候,对应一个客户端,返回一个对应的Socket对象
//定义一个循环不断的接收客户端的连接请求
while (true){
//开始接收客户端与服务器端之间连接
Socket socket = ss.accept();
new ServerReaderThread(socket).start();
}
}
}
//定义与客户端连接连接操作的线程类
class ServerReaderThread extends Thread{
private Socket socket;
ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
//获取与客户端通道中的字节输入流对象
try {
InputStream is = socket.getInputStream();
//将字节输入流对象包装成字符流
InputStreamReader isr = new InputStreamReader(is);
//使用字符缓冲输入流
BufferedReader br = new BufferedReader(isr);
//ip
String ip = socket.getInetAddress().getHostAddress();
String hostName = socket.getInetAddress().getHostName();
//按照行来读取
String line;
while ((line=br.readLine())!=null){
//获取当前时间
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date2 = sdf.format(date);
System.out.println(date2);
System.out.println(ip+":"+hostName+"发送来数据:"+line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}