课程介绍
1. 设计模式概述
产生背景
概念&学习的必要性
设计模式分类
2. UML
类图表示法
类和接口的表示方法
关联关系表示方法
聚合和组合
依赖、继承、实现
设计原则
开闭原则
package org.malred.parttern.openclose;
// 抽象皮肤类
public abstract class AbstractSkin {
// 带abstract的方法,要求子类必须实现
// 显示皮肤
public abstract void display();
}
package org.malred.parttern.openclose;
// 默认皮肤类
public class DefaultSkin extends AbstractSkin {
@Override
public void display() {
System.out.println("默认皮肤");
}
}
package org.malred.parttern.openclose;
public class HeimaSkin extends AbstractSkin {
@Override
public void display() {
System.out.println("黑马皮肤");
}
}
package org.malred.parttern.openclose;
// 搜狗输入法
public class SougouInput {
private AbstractSkin skin;
public void setSkin(AbstractSkin skin) {
this.skin = skin;
}
public void display() {
skin.display();
}
}
package org.malred.parttern.openclose;
public class Client {
public static void main(String[] args) {
// 1. 创建搜狗输入法对象
SougouInput input=new SougouInput();
// 2. 创建皮肤对象
DefaultSkin skin=new DefaultSkin();
// 3. 皮肤设置到输入法
input.setSkin(skin);
// 4. 显示皮肤
input.display();
// 切换
input.setSkin(new HeimaSkin());
input.display();
}
}
里氏替换原则
package org.malred.parttern.lishi.before;
public class RectangleDemo {
public static void main(String[] args) {
// 创建长方形对象
Rectangle r = new Rectangle();
// 设置长宽
r.setLength(20);
r.setWidth(10);
// 扩宽
resize(r);
// 打印长宽
printLengthAndWidth(r);
System.out.println("==========================");
// 创建正方形对象
Square s = new Square();
// 设置长宽
s.setLength(10);
// 扩宽
resize(s);
// 打印长宽
printLengthAndWidth(s);
}
// 扩宽方法
public static void resize(Rectangle rectangle) {
// 宽如果比长小, 就扩宽
while (rectangle.getWidth() <= rectangle.getLength()) {
rectangle.setWidth(rectangle.getWidth() + 1);
}
}
// 打印长宽
public static void printLengthAndWidth(Rectangle rectangle) {
System.out.println(rectangle.getLength());
System.out.println(rectangle.getWidth());
}
}
package org.malred.parttern.lishi.before;
// 长方形类
public class Rectangle {
private double length;
private double width;
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
}
package org.malred.parttern.lishi.before;
// 正方形类
public class Square extends Rectangle {
@Override
public void setLength(double length) {
super.setLength(length);
super.setWidth(length);
}
@Override
public void setWidth(double width) {
super.setLength(width);
super.setWidth(width);
}
}
package org.malred.parttern.lishi.after;
public class RectangleDemo {
public static void main(String[] args) {
// 创建长方形对象
Rectangle r = new Rectangle();
r.setLength(20);
r.setWidth(10);
// 调用方法后扩宽
resize(r);
printLengthAndWidth(r);
}
// 扩宽
public static void resize(Rectangle rectangle) {
// 宽如果比长小, 就扩宽
while (rectangle.getWidth() <= rectangle.getLength()) {
rectangle.setWidth(rectangle.getWidth() + 1);
}
}
// 打印
public static void printLengthAndWidth(Quadrilateral quadrilateral) {
System.out.println(quadrilateral.getLength());
System.out.println(quadrilateral.getWidth());
}
}
package org.malred.parttern.lishi.after;
// 四边形接口
public interface Quadrilateral {
// 获取长
double getLength();
// 获取宽
double getWidth();
}
package org.malred.parttern.lishi.after;
// 长方形
public class Rectangle implements Quadrilateral {
private double length;
private double width;
@Override
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
@Override
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
}
package org.malred.parttern.lishi.after;
// 正方形
public class Square implements Quadrilateral {
private double side;
public double getSide() {
return side;
}
public void setSide(double side) {
this.side = side;
}
@Override
public double getLength() {
return side;
}
@Override
public double getWidth() {
return side;
}
}
依赖倒转原则
依赖倒转原则是开闭原则的具体实现
package org.malred.parttern.reverse.before;
public class ComputerDemo {
public static void main(String[] args) {
// 创建组件
XiJieHardDisk disk = new XiJieHardDisk();
IntelCPU cpu = new IntelCPU();
KingstonMemory memory = new KingstonMemory();
// 创建计算机
Computer c = new Computer();
// 组装计算机
c.setCpu(cpu);
c.setHardDisk(disk);
c.setMemory(memory);
// 运行计算机
c.run();
}
}
package org.malred.parttern.reverse.before;
public class Computer {
private XiJieHardDisk hardDisk;
private IntelCPU cpu;
private KingstonMemory memory;
public void run() {
System.out.println("运行计算机");
cpu.run();
String s = hardDisk.get();
System.out.println("从硬盘获取数据: " + s);
memory.save();
}
public XiJieHardDisk getHardDisk() {
return hardDisk;
}
public void setHardDisk(XiJieHardDisk hardDisk) {
this.hardDisk = hardDisk;
}
public IntelCPU getCpu() {
return cpu;
}
public void setCpu(IntelCPU cpu) {
this.cpu = cpu;
}
public KingstonMemory getMemory() {
return memory;
}
public void setMemory(KingstonMemory memory) {
this.memory = memory;
}
}
package org.malred.parttern.reverse.before;
// 金士顿内存条
public class KingstonMemory {
public void save() {
System.out.println("使用金士顿内存条");
}
}
package org.malred.parttern.reverse.before;
// intel cpu
public class IntelCPU {
public void run() {
System.out.println("使用intel处理器");
}
}
package org.malred.parttern.reverse.before;
// 希捷硬盘
public class XiJieHardDisk {
// 存储数据
public void save(String data) {
System.out.println("使用希捷硬盘存储数据: " + data);
}
// 获取数据
public String get() {
System.out.println("使用希捷硬盘获取数据");
return "数据";
}
}
package org.malred.parttern.reverse.after;
public class ComputerDemo {
public static void main(String[] args) {
// 创建组件
HardDisk disk = new XiJieHardDisk();
CPU cpu = new IntelCPU();
Memory memory = new KingstonMemory();
// 创建计算机
Computer c = new Computer();
// 组装计算机
c.setCpu(cpu);
c.setHardDisk(disk);
c.setMemory(memory);
// 运行计算机
c.run();
}
}
package org.malred.parttern.reverse.after;
// 硬盘接口
public interface HardDisk {
// 存储数据
public void save(String data);
// 获取数据
public String get();
}
package org.malred.parttern.reverse.after;
// 希捷硬盘
public class XiJieHardDisk implements HardDisk{
// 存储数据
public void save(String data) {
System.out.println("使用希捷硬盘存储数据: " + data);
}
// 获取数据
public String get() {
System.out.println("使用希捷硬盘获取数据");
return "数据";
}
}
package org.malred.parttern.reverse.after;
// intel cpu
public class IntelCPU implements CPU {
public void run() {
System.out.println("使用intel处理器");
}
}
package org.malred.parttern.reverse.after;
// CPU接口
public interface CPU {
// 运行cpu
public void run();
}
package org.malred.parttern.reverse.after;
public class Computer {
private HardDisk hardDisk;
private CPU cpu;
private Memory memory;
public void run() {
System.out.println("运行计算机");
cpu.run();
String s = hardDisk.get();
System.out.println("从硬盘获取数据: " + s);
memory.save();
}
public HardDisk getHardDisk() {
return hardDisk;
}
public void setHardDisk(HardDisk hardDisk) {
this.hardDisk = hardDisk;
}
public CPU getCpu() {
return cpu;
}
public void setCpu(CPU cpu) {
this.cpu = cpu;
}
public Memory getMemory() {
return memory;
}
public void setMemory(Memory memory) {
this.memory = memory;
}
}
package org.malred.parttern.reverse.after;
// 金士顿内存条
public class KingstonMemory implements Memory {
public void save() {
System.out.println("使用金士顿内存条");
}
}
package org.malred.parttern.reverse.after;
// 内存接口
public interface Memory {
// 存储数据
public void save();
}
接口隔离原则
package org.malred.parttern.interfaceIsolate.before;
public class Client {
public static void main(String[] args) {
HeimaSafelyDoor door = new HeimaSafelyDoor();
door.waterProof();
door.fireProof();
door.antiTheft();
}
}
package org.malred.parttern.interfaceIsolate.before;
public class HeimaSafelyDoor implements SafelyDoor {
@Override
public void antiTheft() {
System.out.println("黑马防盗");
}
@Override
public void fireProof() {
System.out.println("黑马防火");
}
@Override
public void waterProof() {
System.out.println("黑马防水");
}
}
package org.malred.parttern.interfaceIsolate.before;
// 安全门接口
public interface SafelyDoor {
// 防盗
void antiTheft();
// 防火
void fireProof();
// 防水
void waterProof();
}
package org.malred.parttern.interfaceIsolate.after;
public class Client {
public static void main(String[] args) {
HeiMaSafetyDoor door = new HeiMaSafetyDoor();
door.waterproof();
door.fireproof();
door.antiTheft();
ItcastSafetyDoor it_door = new ItcastSafetyDoor();
it_door.antiTheft();
it_door.fireproof();
}
}
package org.malred.parttern.interfaceIsolate.after;
// 防水接口
public interface Waterproof {
void waterproof();
}
package org.malred.parttern.interfaceIsolate.after;
// 防火接口
public interface Fireproof {
void fireproof();
}
package org.malred.parttern.interfaceIsolate.after;
// 防盗接口
public interface AntiTheft {
void antiTheft();
}
package org.malred.parttern.interfaceIsolate.after;
public class ItcastSafetyDoor implements AntiTheft, Fireproof {
@Override
public void antiTheft() {
System.out.println("传智防盗");
}
@Override
public void fireproof() {
System.out.println("传智防火");
}
}
package org.malred.parttern.interfaceIsolate.after;
public class HeiMaSafetyDoor implements AntiTheft, Waterproof, Fireproof {
@Override
public void antiTheft() {
System.out.println("黑马防盗");
}
@Override
public void fireproof() {
System.out.println("黑马防火");
}
@Override
public void waterproof() {
System.out.println("黑马防水");
}
}
迪米特法则
package org.malred.parttern.dimite;
public class Agent {
private Star star;
private Fans fans;
private Company company;
public void setStar(Star star) {
this.star = star;
}
public void setFans(Fans fans) {
this.fans = fans;
}
public void setCompany(Company company) {
this.company = company;
}
// 和粉丝见面
public void meeting() {
System.out.println(star.getName() + "和粉丝" + fans.getName() + "见面");
}
// 和媒体公司商谈
public void business() {
System.out.println(star.getName() + "和" + company.getName() + "洽谈");
}
}
package org.malred.parttern.dimite;
public class Company {
private String name;
public Company(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
package org.malred.parttern.dimite;
public class Fans {
private String name;
public Fans(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
package org.malred.parttern.dimite;
public class Star {
private String name;
public Star(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
package org.malred.parttern.dimite;
public class Client {
public static void main(String[] args) {
Agent agent = new Agent();
Star star = new Star("车银优");
agent.setStar(star);
Fans fans = new Fans("路人甲");
agent.setFans(fans);
Company company = new Company("黑马传媒");
agent.setCompany(company);
agent.meeting();
agent.business();
}
}
合成复用原则
创建者模式
单例模式
实现
package org.malred.pattern.singleton.demo1;
// 饿汉式: 静态成员变量方式
public class Singleton {
// 2. 在本类中创建本类对象
private static Singleton instance = new Singleton();
// 1. 私有构造方法
private Singleton() {
}
// 3. 提供公共访问方式,让外界获取对象
public static Singleton getInstance() {
return instance;
}
}
package org.malred.pattern.singleton.demo1;
public class Client {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
// 判断获取的是不是同一个对象
// == 比较对象是比较在内存中的位置
System.out.println(instance == instance1);
}
}
package org.malred.pattern.singleton.demo2;
public class Client {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance==instance1);
}
}
package org.malred.pattern.singleton.demo2;
// 饿汉式: 静态代码块方式
public class Singleton {
// 2. 声明singleton类型的变量
private static Singleton instance; // null
// 3. 在静态代码块中赋值
static {
instance = new Singleton();
}
// 1. 私有构造方法
private Singleton() {
}
// 4. 对外提供获取方法
public static Singleton getInstance() {
return instance;
}
}
package org.malred.pattern.singleton.demo3;
// 懒汉式
public class Singleton {
// 声明Singleton类型的变量instance
private static Singleton instance;
// 私有构造方法
private Singleton() {
}
// 对外提供访问方式
// public static Singleton getInstance() {
// 加上synchronized,让操作该对象的线程有一个同步锁,不会让其他线程操作该对象
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
package org.malred.pattern.singleton.demo3;
public class Client {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance == instance1);
}
}
package org.malred.pattern.singleton.demo4;
// 懒汉式: 双重检查锁
public class Singleton {
// 声明Singleton类型的变量instance
// 防止指令重排序导致可能的空指针问题
private static volatile Singleton instance;
// 私有构造方法
private Singleton() {
}
// 对外提供公共的访问方式
public static Singleton getInstance() {
// 第一次判断, instance不为null, 直接返回
if (instance == null) {
synchronized (Singleton.class) {
// 第二次判断
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
package org.malred.pattern.singleton.demo4;
public class Client {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance == instance1);
}
}
package org.malred.pattern.singleton.demo5;
public class Client {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance == instance1);
}
}
package org.malred.pattern.singleton.demo5;
// 懒汉式: 静态内部类
public class Singleton {
// 私有构造方法
private Singleton() {
}
// 提供公共访问方式
public static Singleton getInstance() {
return singletonHolder.INSTANCE;
}
// 定义静态内部类
private static class singletonHolder {
// 内部类中声明并初始化外部类对象
private static Singleton INSTANCE = new Singleton();
}
}
package org.malred.pattern.singleton.demo6;
// 恶汉式(浪费内存空间): 枚举方式
public enum Singleton {
INSTANCE;
}
package org.malred.pattern.singleton.demo6;
public class Client {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance1 = Singleton.INSTANCE;
System.out.println(instance == instance1);
}
}
它文档里的恶汉式应该是打错了的饿汉式
存在的问题
序列化和反序列化
package org.malred.pattern.singleton.demo7;
import java.io.*;
// 测试反射破坏单例模式
public class Client {
public static final String PATH = "F:\\codes\\backend\\java\\design_parttern\\src\\main\\java\\org\\malred\\pattern\\singleton\\demo7\\a.txt";
public static void main(String[] args) throws Exception {
// writeObject2File();
// 两次读到的对象地址不同, 单例模式被破坏
readObjectFromFile();
readObjectFromFile();
}
// 向文件中写入数据(对象)
public static void writeObject2File() throws Exception {
// 1. 获取Singleton对象
Singleton instance = Singleton.getInstance();
// 2. 创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(PATH));
// 3. 写对象
oos.writeObject(instance);
// 4. 释放资源
oos.close();
}
// 从文件中读取数据(对象)
public static void readObjectFromFile() throws Exception {
// 1. 创建对象输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PATH));
// 2. 读取对象
Singleton instance = (Singleton) ois.readObject();
System.out.println(instance);
// 释放资源
ois.close();
}
}
package org.malred.pattern.singleton.demo7;
import java.io.Serializable;
public class Singleton implements Serializable {
// 私有构造方法
private Singleton() {
}
// 提供公共访问方式
public static Singleton getInstance() {
return Singleton.singletonHolder.INSTANCE;
}
// 定义静态内部类
private static class singletonHolder {
// 内部类中声明并初始化外部类对象
private static Singleton INSTANCE = new Singleton();
}
}
反射
package org.malred.pattern.singleton.demo8;
import java.lang.reflect.Constructor;
// 测试通过反射破坏单例模式
public class Client {
public static void main(String[] args) throws Exception {
// 1. 获取Singleton字节码对象
Class clazz = Singleton.class;
// 2. 获取无参构造方法对象
Constructor constructor = clazz.getDeclaredConstructor();
// 3. 取消访问检查
constructor.setAccessible(true);
// 4. 创建Singleton对象
Singleton s1 = (Singleton) constructor.newInstance();
Singleton s2 = (Singleton) constructor.newInstance();
// false -> 破坏了单例模式
System.out.println(s1 == s2);
}
}
解决方法
序列化
package org.malred.pattern.singleton.demo7;
import java.io.Serializable;
public class Singleton implements Serializable {
// 私有构造方法
private Singleton() {
}
// 提供公共访问方式
public static Singleton getInstance() {
return Singleton.singletonHolder.INSTANCE;
}
// 反序列化时,会自动调用该方法,返回该方法的返回值 -> 解决序列化破坏单例模式问题
public Object readResolve() {
return singletonHolder.INSTANCE;
}
// 定义静态内部类
private static class singletonHolder {
// 内部类中声明并初始化外部类对象
private static Singleton INSTANCE = new Singleton();
}
}
反射
package org.malred.pattern.singleton.demo8;
public class Singleton {
// 静态属性, 所有实例共享
private static boolean flag = false;
// 私有构造方法
private Singleton() {
// 解决反射多次调用无参构造创建对象破坏单例模式
synchronized (Singleton.class) {
// 如果flag为true, 说明是第二次访问, 抛异常
if (flag) {
throw new RuntimeException("不能创建多个对象");
}
// flag设置为true
flag = true;
}
}
// 提供公共访问方式
public static Singleton getInstance() {
return Singleton.singletonHolder.INSTANCE;
}
// 定义静态内部类
private static class singletonHolder {
// 内部类中声明并初始化外部类对象
private static Singleton INSTANCE = new Singleton();
}
}
JDK - Runtime 类
package org.malred.pattern.singleton.JDK;
import java.io.InputStream;
public class RuntimeDemo {
public static void main(String[] args) throws Exception {
// 获取Runtime对象
Runtime runtime = Runtime.getRuntime();
// 调用exec
Process process = runtime.exec("ipconfig");
// 调用process的获取输入流的方法
InputStream is = process.getInputStream();
byte[] arr = new byte[1024 * 1024 * 100];
// 读取数据
int len = is.read(arr); // 返回读到的数据的个数
// 将字节数组转换为字符串输出到控制台
System.out.println(new String(arr, 0, len, "GBK"));
}
}
工厂模式
点咖啡案例
package org.malred.pattern.factory.before;
public class client {
public static void main(String[] args) {
CoffeeStore store = new CoffeeStore();
Coffee coffee = store.orderCoffee("latte");
System.out.println(coffee.getName());
}
}
package org.malred.pattern.factory.before;
// 咖啡店
public class CoffeeStore {
public Coffee orderCoffee(String type) {
// 根据不同类型创建不同咖啡对象
Coffee coffee = null;
if ("american".equals(type)) {
coffee = new AmericanCoffee();
} else if ("latte".equals(type)) {
coffee = new LatteCoffee();
} else {
throw new RuntimeException("没有该种咖啡");
}
// 加配料
coffee.addSugar();
coffee.addMilk();
return coffee;
}
}
package org.malred.pattern.factory.before;
public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "拿铁咖啡";
}
}
package org.malred.pattern.factory.before;
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "美式咖啡";
}
}
package org.malred.pattern.factory.before;
// 咖啡类
public abstract class Coffee {
public abstract String getName();
public void addSugar() {
System.out.println("加糖");
}
public void addMilk() {
System.out.println("加奶");
}
}
简单工厂模式
package org.malred.pattern.factory.SimpleFactory;
public class client {
public static void main(String[] args) {
CoffeeStore store = new CoffeeStore();
Coffee coffee = store.orderCoffee("latte");
System.out.println(coffee.getName());
}
}
package org.malred.pattern.factory.SimpleFactory;
public class SimpleCoffeeFactory {
public Coffee createCoffee(String type) {
// 根据不同类型创建不同咖啡对象
Coffee coffee = null;
if ("american".equals(type)) {
coffee = new AmericanCoffee();
} else if ("latte".equals(type)) {
coffee = new LatteCoffee();
} else {
throw new RuntimeException("没有该种咖啡");
}
return coffee;
}
}
package org.malred.pattern.factory.SimpleFactory;
// 咖啡店
public class CoffeeStore {
public Coffee orderCoffee(String type) {
SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
Coffee coffee = factory.createCoffee(type);
coffee.addMilk();
coffee.addSugar();
return coffee;
}
}
工厂方法模式
package org.malred.pattern.factory.FactoryMethod;
public class Client {
public static void main(String[] args) {
CoffeeStore coffeeStore = new CoffeeStore();
coffeeStore.setFactory(new AmericanCoffeeFactory());
Coffee coffee = coffeeStore.orderCoffee();
System.out.println(coffee.getName());
}
}
package org.malred.pattern.factory.FactoryMethod;
// 咖啡店
public class CoffeeStore {
private CoffeeFactory factory;
public void setFactory(CoffeeFactory factory) {
this.factory = factory;
}
public Coffee orderCoffee() {
Coffee coffee = factory.createCoffee();
coffee.addMilk();
coffee.addSugar();
return coffee;
}
}
package org.malred.pattern.factory.FactoryMethod;
public class LatteCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {
return new LatteCoffee();
}
}
package org.malred.pattern.factory.FactoryMethod;
public class AmericanCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
package org.malred.pattern.factory.FactoryMethod;
// 抽象工厂
public interface CoffeeFactory {
// 创建咖啡对象的方法
public Coffee createCoffee();
}
抽象工厂模式
package org.malred.pattern.factory.AbstractFactory;
public class Client {
public static void main(String[] args) {
ItalyDessertFactory factory = new ItalyDessertFactory();
Coffee coffee = factory.createCoffee();
Dessert dessert = factory.createDessert();
System.out.println(coffee.getName());
dessert.show();
}
}
package org.malred.pattern.factory.AbstractFactory;
public class ItalyDessertFactory implements DessertFactory {
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
@Override
public Dessert createDessert() {
return new Trimisu();
}
}
package org.malred.pattern.factory.AbstractFactory;
public class AmericanDessertFactory implements DessertFactory {
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
@Override
public Dessert createDessert() {
return new MatchaMousse();
}
}
package org.malred.pattern.factory.AbstractFactory;
public interface DessertFactory {
Coffee createCoffee();
Dessert createDessert();
}
package org.malred.pattern.factory.AbstractFactory;
public class MatchaMousse extends Dessert {
@Override
public void show() {
System.out.println("抹茶慕斯");
}
}
package org.malred.pattern.factory.AbstractFactory;
public class Trimisu extends Dessert {
@Override
public void show() {
System.out.println("提拉米苏");
}
}
package org.malred.pattern.factory.AbstractFactory;
public abstract class Dessert {
public abstract void show();
}