单例、工厂、建造者、原型、适配器、桥接
一、概述
设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。 GOF 23
二、OOP七大原则
OOP:面向对象程序设计
三、单例模式
饿汉式单例
public class Hungry {
private byte[] buffer1=new byte[1024];
private byte[] buffer2=new byte[1024];
private byte[] buffer3=new byte[1024];
private Hungry() {
}
private static final Hungry hungry=new Hungry();
public Hungry getHungty() {
return hungry;
}
}
一上来就加载出所有的类,容易造成资源的浪费!
懒汉式单例
public class LazyMan {
private LazyMan() {
}
private static LazyMan lazeman;
private static LazyMan getLazyMan() {
if (lazeman==null) {
lazeman=new LazyMan();
}
return lazeman;
}
}
需要的时候在new出对象
public class LazyMan {
private LazyMan() {
System.out.println("懒汉式单例:"+Thread.currentThread().getName());
}
private static volatile LazyMan lazeman;
//双重锁模式的懒汉式单例 DCL懒汉式
private static LazyMan getLazyMan() {
if (lazeman==null) {
synchronized (LazyMan.class){
if (lazeman==null) {
lazeman=new LazyMan();//不是原子性操作
/**new对象的过程:
* 分配内存空间
* 执行构造函数,初始化对象
* 把对象执行内存空间
* ==>可能会进行重排,使用volatile禁止进行指令重排序
*/
}
}
}
return lazeman;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getLazyMan();
}).start();
}
}
}
> "懒汉式单例:"+Thread.currentThread().getName() [只出现一次此值]
public static void main(String[] args) throws Exception {
LazyMan lazyMan1 = LazyMan.getLazyMan();
//反射会破坏单例模式
Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
LazyMan lazyMan2 = constructor.newInstance();
constructor.setAccessible(true);
System.out.println(lazyMan1.hashCode());
System.out.println(lazyMan2.hashCode());
}
System.out.println(enumSingle1.hashCode());
System.out.println(enumSingle2.hashCode());
> 509886383
> 1854778591
private LazyMan() {
//加锁
synchronized (LazyMan.class) {
if (lazeman!=null) {
throw new RuntimeException("不要试图用反射破坏单例模式");
}
}
}
System.out.println(enumSingle1.hashCode());
System.out.println(enumSingle2.hashCode());
> 509886383
> 509886383
public static void main(String[] args) throws Exception {
//双重反射破坏单例模式,两个对象都是反射获得的
Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
LazyMan lazyMan1 = constructor.newInstance();
LazyMan lazyMan2 = constructor.newInstance();
constructor.setAccessible(true);
System.out.println(lazyMan1.hashCode());
System.out.println(lazyMan2.hashCode());
}
System.out.println(enumSingle1.hashCode());
System.out.println(enumSingle2.hashCode());
> 509886383
> 1854778591
private static boolean flag=false;
private LazyMan() {
synchronized (LazyMan.class) {
if (flag == false) {
flag = true;
} else {
throw new RuntimeException("不要试图用反射破坏单例模式");
}
}
}
System.out.println(enumSingle1.hashCode());
System.out.println(enumSingle2.hashCode());
> 509886383
> 509886383
public static void main(String[] args) throws Exception {
Field newflag = LazyMan.class.getDeclaredField("flag");
newflag.setAccessible(true);
//反射会破坏单例模式
Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
LazyMan lazyMan1 = constructor.newInstance();
newflag.set(flag,false);
LazyMan lazyMan2 = constructor.newInstance();
constructor.setAccessible(true);
System.out.println(lazyMan1.hashCode());
System.out.println(lazyMan2.hashCode());
}
System.out.println(enumSingle1.hashCode());
System.out.println(enumSingle2.hashCode());
> 509886383
> 1854778591
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() {
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle enumSingle1=EnumSingle.INSTANCE;
//通过反编译class文件可以得到enum的源文件构造器的参数
Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
EnumSingle enumSingle2=EnumSingle.INSTANCE;
System.out.println(enumSingle1.hashCode());
System.out.println(enumSingle2.hashCode());
}
}
System.out.println(enumSingle1.hashCode());
System.out.println(enumSingle2.hashCode());
> 557041912
> 557041912
静态内部类
//静态内部类
public class Holder {
public Holder() {
}
public Holder getHolder() {
return InnerClass.holder;
}
public static class InnerClass{
private static final Holder holder=new Holder();
}
}
反编译class文件
- 进入.class文件目录->javap -p Name.class ->会生成方法目录
- 第三方插件:进入.class文件目录->jad -s java EnumSingle. class
- 通过ieda进行反编译
四、工厂模式
简单工厂模式
又叫静态工厂模式 实现统一工厂

public interface Fruits {
void name();
}
public class Apple implements Fruits{
@Override
public void name() {
System.out.println("苹果🍎");
}
}
public class Banana implements Fruits{
@Override
public void name() {
System.out.println("香蕉🍌");
}
}
//静态工厂🏭
public class FruitFactory {
public static Fruits getFruit(String Fruit) {
//方法一
if (Fruit.equals("苹果")) {
return new Apple();
} else if (Fruit.equals("香蕉")) {
return new Banana();
} else {
return null;
}
//方法一
// switch (Fruit) {
// case "苹果" :return new Apple();
// case "香蕉": return new Banana();
// default:return null;
// }
}
//方法二
public static Fruits getApple(){
return new Apple();
}
public static Fruits getBanan(){
return new Banana();
}
}
public class Test {
public static void main(String[] args) {
//原始方法
Apple apple = new Apple();
Banana banana = new Banana();
apple.name();
banana.name();
//静态工厂方法一
FruitFactory.getFruit("苹果").name();
FruitFactory.getFruit("香蕉").name();
//静态工厂
FruitFactory.getApple().name();
FruitFactory.getBanan().name();
}
}
工厂方法模式
实现统一接口,每一个类都会有一个工厂方法
统一水果接口:
public interface Fruits {
void name();
}
统一工厂接口:
public interface FruitFactory {
Fruits getFruit();
}
水果:
public class Apple implements Fruits {
@Override
public void name() {
System.out.println("苹果🍎");
}
}
public class Banana implements Fruits {
@Override
public void name() {
System.out.println("香蕉🍌");
}
}
水果工厂:
public class AppleFactory implements FruitFactory{
@Override
public Fruits getFruit() {
return new Apple();
}
}
public class BananFactory implements FruitFactory{
@Override
public Fruits getFruit() {
return new Banana();
}
}
测试类:
public class Test {
public static void main(String[] args) {
new AppleFactory().getFruit().name();
new BananFactory().getFruit().name();
}
}
抽象工厂模式
提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类!


//手机产品接口
public interface IphoneProduct {
void start();
void shutdown();
void callup();
void sendSMS();
}
//路由器产品接口
public interface IRouterProduct {
void start();
void shutdown();
void openWifi();
void setting();
}
public class XiaomiPhone implements IphoneProduct {
@Override
public void start() {
System.out.println("小米手机开机");
}
@Override
public void shutdown() {
System.out.println("小米手机关机");
}
@Override
public void callup() {
System.out.println("小米手机打电话");
}
@Override
public void sendSMS() {
System.out.println("小米手机发短信");
}
}
public class HuaweiPhone implements IphoneProduct {
@Override
public void start() {
System.out.println("华为手机开机");
}
@Override
public void shutdown() {
System.out.println("华为手机关机");
}
@Override
public void callup() {
System.out.println("华为手机打电话");
}
@Override
public void sendSMS() {
System.out.println("华为手机发短信");
}
}
public class XiaomiRouter implements IRouterProduct{
@Override
public void start() {
System.out.println("小米路由器打开");
}
@Override
public void shutdown() {
System.out.println("小米路由器关闭");
}
@Override
public void openWifi() {
System.out.println("小米路由器打开WiFi");
}
@Override
public void setting() {
System.out.println("小米路由器设置密码");
}
}
public class HuaweiRouter implements IRouterProduct{
@Override
public void start() {
System.out.println("华为路由器打开");
}
@Override
public void shutdown() {
System.out.println("华为路由器关闭");
}
@Override
public void openWifi() {
System.out.println("华为路由器打开WiFi");
}
@Override
public void setting() {
System.out.println("华为路由器设置密码");
}
}
//生产手机和路由器接口
public interface IProductFactory {
IphoneProduct phoneProduct();
IRouterProduct RouterProduct();
}
//华为工厂,生产手机和路由器
public class HuaweiFactory implements IProductFactory{
@Override
public IphoneProduct phoneProduct() {
return new HuaweiPhone();
}
@Override
public IRouterProduct RouterProduct() {
return new HuaweiRouter();
}
}
//小米工厂,生产手机和路由器
public class XiaomiFactory implements IProductFactory{
@Override
public IphoneProduct phoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct RouterProduct() {
return new XiaomiRouter();
}
}
//用户
public class client {
public static void main(String[] args) {
System.out.println("===============小米系列功能===============");
XiaomiFactory xiaomiFactory = new XiaomiFactory();
IphoneProduct iphoneProduct = xiaomiFactory.phoneProduct();
iphoneProduct.start();
iphoneProduct.sendSMS();
System.out.println("===============华为系列功能===============");
HuaweiFactory huaweiFactory = new HuaweiFactory();
IRouterProduct iRouterProduct = huaweiFactory.RouterProduct();
iRouterProduct.openWifi();
iRouterProduct.setting();
}
}

五、建造者模式

种类一:指挥者
//抽象的建造者:方法
public abstract class Builder {
abstract void builderA();//地基
abstract void builderB();//钢筋水泥
abstract void builderC();//线缆
abstract void builderD();//粉刷
abstract Product getProduct();//完工
}
//产品:房子
public class Product {
private String builderA;
private String builderB;
private String builderC;
private String builderD;
public String getBuilderA() {
return builderA;
}
public void setBuilderA(String builderA) {
this.builderA = builderA;
}
public String getBuilderB() {
return builderB;
}
public void setBuilderB(String builderB) {
this.builderB = builderB;
}
public String getBuilderC() {
return builderC;
}
public void setBuilderC(String builderC) {
this.builderC = builderC;
}
public String getBuilderD() {
return builderD;
}
public void setBuilderD(String builderD) {
this.builderD = builderD;
}
@Override
public String toString() {
return "Product{" +
"builderA='" + builderA + '\'' +
", builderB='" + builderB + '\'' +
", builderC='" + builderC + '\'' +
", builderD='" + builderD + '\'' +
'}';
}
}
//工人
public class Worker extends Builder{
private Product product;
public Worker(){
product=new Product();
}
@Override
void builderA() {
product.setBuilderA("地基");
System.out.println("地基");
}
@Override
void builderB() {
product.setBuilderB("钢筋水泥");
System.out.println("钢筋水泥");
}
@Override
void builderC() {
product.setBuilderC("线缆");
System.out.println("线缆");
}
@Override
void builderD() {
product.setBuilderD("粉刷");
System.out.println("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
//指挥:最核心
public class Director {
public Product builder(Builder builder){
builder.builderA();
builder.builderB();
builder.builderC();
builder.builderD();
return builder.getProduct();
}
}
//用户:拿到产品
public class Test {
public static void main(String[] args) {
Director director = new Director();
Product product = director.builder(new Worker());
System.out.println(product.toString());
}
}
> 地基
> 钢筋水泥
> 线缆
> 粉刷
> Product{builderA='地基', builderB='钢筋水泥', builderC='线缆', builderD='粉刷'}
种类二:用户指挥
public abstract class Builder {
abstract Builder builderA(String msg);//汉堡
abstract Builder builderB(String msg);//可乐
abstract Builder builderC(String msg);//甜点
abstract Builder builderD(String msg);//薯片
abstract Product getProduct();
}
//产品:套餐
public class Product {
private String builderA="汉堡";
private String builderB="可乐";
private String builderC="甜点";
private String builderD="薯片";
public String getBuilderA() {
return builderA;
}
public void setBuilderA(String builderA) {
this.builderA = builderA;
}
public String getBuilderB() {
return builderB;
}
public void setBuilderB(String builderB) {
this.builderB = builderB;
}
public String getBuilderC() {
return builderC;
}
public void setBuilderC(String builderC) {
this.builderC = builderC;
}
public String getBuilderD() {
return builderD;
}
public void setBuilderD(String builderD) {
this.builderD = builderD;
}
@Override
public String toString() {
return "Product{" +
"builderA='" + builderA + '\'' +
", builderB='" + builderB + '\'' +
", builderC='" + builderC + '\'' +
", builderD='" + builderD + '\'' +
'}';
}
}
//服务员
public class Worker extends Builder{
private Product product;
public Worker(){
product=new Product();
}
@Override
Builder builderA(String msg) {
product.setBuilderA(msg);
return this;
}
@Override
Builder builderB(String msg) {
product.setBuilderB(msg);
return this;
}
@Override
Builder builderC(String msg) {
product.setBuilderC(msg);
return this;
}
@Override
Builder builderD(String msg) {
product.setBuilderD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
public class Test {
public static void main(String[] args) {
Worker worker = new Worker();
//链式编程:在原来基础上,可以自由组合,如果不组合,也有默认套餐
Product product = worker.builderA("全家桶").builderB("雪碧").getProduct();
System.out.println(product.toString());
}
}
> Product{builderA='全家桶', builderB='雪碧', builderC='甜点', builderD='薯片'}
总结
六、原型模式
基于原型创建对象 深度克隆 浅克隆

浅克隆
拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
原型:要实现Coneable接口,重写其clone方法
import java.util.Date;
public class Video implements Cloneable{
private String id;
private Date createDate;
public Video() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Video(String id, Date createDate) {
this.id = id;
this.createDate = createDate;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@Override
public String toString() {
return "Video{" +
"id='" + id + '\'' +
", createDate='" + createDate + '\'' +
'}';
}
}
基于原型创建的对象
//浅克隆
public class newVideo01 {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date();
Video v1 = new Video("65001",date);
System.out.println(v1);
System.out.println(v1.hashCode());
Video v2 = (Video) v1.clone();
System.out.println(v2);
System.out.println(v2.hashCode());
}
}
> Video{id='65001', createDate='Wed Mar 16 08:44:48 CST 2022'}
> 1597462040
> Video{id='65001', createDate='Wed Mar 16 08:44:48 CST 2022'}
> 403716510
浅克隆时导致的问题
public class newVideo01 {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date();
Video v1 = new Video("65001",date);
Video v2 = (Video) v1.clone();
System.out.println(v1);
System.out.println(v1.hashCode());
System.out.println(v2);
System.out.println(v2.hashCode());
//========================================
//v1.setCreateDate(new Date(34271765));
//v1.setId("37768"); //为什么通过set重新设置属性不会引起v2的改变
date.setTime(7395273); //而这种方式就会引起v2的同时变化
System.out.println(v1);
System.out.println(v1.hashCode());
System.out.println(v2);
System.out.println(v2.hashCode());
}
}
Video{id='65001', createDate='Wed Mar 16 09:03:59 CST 2022'}
403716510
Video{id='65001', createDate='Wed Mar 16 09:03:59 CST 2022'}
853119666
=========================
Video{id='65001', createDate='Thu Jan 01 14:30:24 CST 1970'} //同时改变
403716510
Video{id='65001', createDate='Thu Jan 01 14:30:24 CST 1970'} //同时改变
853119666
深克隆
不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
原型
import java.util.Date;
public class Video implements Cloneable{
private String id;
private Date createDate;
public Video() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Video obj1 = (Video) obj;
obj1.createDate = (Date) this.createDate.clone();
return obj; //为什么返回obj和obj1效果是一样的?
}
public Video(String id, Date createDate) {
this.id = id;
this.createDate = createDate;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@Override
public String toString() {
return "Video{" +
"id='" + id + '\'' +
", createDate='" + createDate + '\'' +
'}';
}
}
import java.util.Date;
public class newVideo01 {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date();
Video v1 = new Video("65001",date);
Video v2 = (Video) v1.clone();
System.out.println(v1);
System.out.println(v1.hashCode());
System.out.println(v2);
System.out.println(v2.hashCode());
System.out.println("=========================");
date.setTime(7395273);
System.out.println(v1);
System.out.println(v1.hashCode());
System.out.println(v2);
System.out.println(v2.hashCode());
}
}
Video{id='65001', createDate='Wed Mar 16 09:32:06 CST 2022'}
403716510
Video{id='65001', createDate='Wed Mar 16 09:32:06 CST 2022'}
853119666
=========================
Video{id='65001', createDate='Thu Jan 01 10:03:15 CST 1970'}
403716510
Video{id='65001', createDate='Wed Mar 16 09:32:06 CST 2022'} //不会改变
853119666
七、适配器模式

案例:电脑通过转换器连接网线

继承方式实现
网线
//网线
public class NetworkCable {
public void getNet() {
System.out.println("连接上了网络⌬");
}
}
转换器抽线接口
public interface NetToUsb {
public void getCable();
}
转换器
//转换器
public class Adater extends NetworkCable implements NetToUsb{
@Override
public void getCable() {
super.getNet();
}
}
电脑
public class Computer {
public void net(NetToUsb Apater) {
Apater.getCable();
}
}
客户端
public class Client {
public static void main(String[] args) {
Computer computer = new Computer();
Adater apater = new Adater();
computer.net(apater);
}
}
> 连接上了网络⌬
组合方式实现
推荐使用,非常灵活,可自由变换接口
网线
//网线
public class NetworkCable {
public void getNet() {
System.out.println("连接上了网络⌬");
}
}
转换器接口
public interface NetToUsb {
public void getCable();
}
转换器
public class Adater02 implements NetToUsb{
NetworkCable networkCable;
public Adater02(NetworkCable networkCable){
this.networkCable=networkCable;
}
@Override
public void getCable() {
networkCable.getNet();
}
}
电脑
public class Computer {
public void net(NetToUsb Apater) {
Apater.getCable();
}
}
客户端
public class Client02 {
public static void main(String[] args) {
Computer computer = new Computer();
NetworkCable networkCable = new NetworkCable();
Adater02 apater02 = new Adater02(networkCable);
computer.net(apater02);
}
}
> 连接上了网络⌬
结构图

小结

八、桥接模式
连接多个纬度


电脑品牌接口
//品牌接口🪢
public interface Brand {
public void info();
}
苹果电脑
public class Apple implements Brand{
@Override
public void info() {
System.out.println("苹果");
}
}
联想电脑
public class Lenovo implements Brand{
@Override
public void info() {
System.out.println("联想");
}
}
抽象电脑类(引入了品牌)
//抽象的电脑类型
public abstract class Computer {
//电脑组合品牌
protected Brand brand;
public Computer(Brand brand) {
this.brand=brand;
}
public void info() {
brand.info();//自带品牌属性
}
}
笔记本电脑
//笔记本
public class Laptop extends Computer{
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.println("笔记本");
}
}
台式电脑
//台式机
public class Desktop extends Computer{
public Desktop(Brand brand){
super(brand);
}
@Override
public void info(){
super.info();
System.out.println("台式机");
}
}
测试
public class Test {
public static void main(String[] args) {
//苹果笔记本
Laptop laptop = new Laptop(new Apple());
laptop.info();
//联想台式机
Desktop desktop = new Desktop(new Lenovo());
desktop.info();
}
}
> 苹果 笔记本
> 联想 台式机
关系:

小结: