23种设计模式
设计模式的分类 总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
OOP七大原则
开闭原则:对扩展开放,对修改关闭
里氏替换原则:继承必须确保超累所拥有的性质在子类中任然成立(尽量不重写父类的方法)
依赖倒置原则:要面向接口编程,不要面向实现编程
单一职责原则:控制类的粒度大小、将对象解耦、提高其内聚性
接口隔离原则:要为各个类创建他们需要的专用接口
迪米特法则:只与你的直接朋友交谈,不跟“陌生人”说话
合成复用原则:尽量先试用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
创建型模式
工厂模式
简单工厂模式
:简单工厂模式是属于创建型模式,又叫做静态工厂方法模式
例如:(直接看代码)
先写一个接口
public interface Car {
void name();
}
定义他的工厂类
//静态工厂模式
//增加一个新的产品,如果不修改代码,做不到!
//开闭原则
public class CarFactory {
//方法一:
public static Car getCar(String car){
if (car.equals("五菱")){
return new WuLing();
}else if (car.equals("特斯拉")){
return new Tesla();
}else {
return null;
}
}
//方法二:
public static Car getWuLing(){
return new WuLing();
}
public static Car getTesla(){
return new Tesla();
}
}
汽车的品牌实现接口
public class Dazhong implements Car{
@Override
public void name() {
System.out.println("大众!");
}
}
public class Tesla implements Car{
@Override
public void name() {
System.out.println("特斯拉!");
}
}
public class WuLing implements Car{
@Override
public void name() {
System.out.println("五菱宏光!");
}
}
消费者买车
public class Consumer {
public static void main(String[] args) {
//接口,所有的实现类!工厂
//Car car = new WuLing();
//Car car2 = new Tesla();
//2.使用工厂类实现
Car car = CarFactory.getCar("五菱");
Car car2 = CarFactory.getCar("特斯拉");
car.name();
car2.name();
}
}
工厂方法模式
:是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。
定义接口
public interface Car {
void name();
}
定义车工厂
//工厂方法模式
public interface CarFactory {
Car getCar();
}
车品牌工厂 :实现车工厂接口
public class MoBaiFactory implements CarFactory{
@Override
public Car getCar() {
return new MoBai();
}
}
public class TeslaFactory implements CarFactory{
@Override
public Car getCar() {
return new Tesla();
}
}
public class WuLingFactory implements CarFactory{
@Override
public Car getCar() {
return new WuLing();
}
}
汽车:实现Car接口
public class MoBai implements Car{
@Override
public void name() {
System.out.println("摩拜单车!");
}
}
public class Tesla implements Car {
@Override
public void name() {
System.out.println("特斯拉!");
}
}
public class WuLing implements Car {
@Override
public void name() {
System.out.println("五菱宏光!");
}
}
消费者可以直接去车工厂提取车,不需要考虑其他
public class Consumer {
public static void main(String[] args) {
Car car = new WuLingFactory().getCar();
Car car2 = new TeslaFactory().getCar();
car.name();
car2.name();
Car car3 = new MoBaiFactory().getCar();
car3.name();
}
}
抽象工厂模式
:抽象工厂是指当有多个抽象角色时使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。
public interface IProductFactory {
//产品工厂 、生产手机与路由器
//生产手机
IphoneProduct iphoneProduct();
//生产路由器
IRouterProduct routerProduct();
}
//手机产品接口
public interface IphoneProduct {
void start();
void shutdown();
void callup();
void sendSMS();
}
public interface IRouterProduct {
//路由器产品接口
void start();
void shutdown();
void openWifi();
void setting();
}
不同手机工厂:需要实现产品接口,并且重写方法
public class HuaweiFactory implements IProductFactory{
@Override
public IphoneProduct iphoneProduct() {
return new HuaweiIphone();
}
@Override
public IRouterProduct routerProduct() {
return new HuaweiIRouter();
}
}
public class XiaomiFactory implements IProductFactory{
@Override
public IphoneProduct iphoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct routerProduct() {
return new XiaomiIRouter();
}
}
不同手机实现手机接口
//华为手机
public class HuaweiIphone 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 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 HuaweiIRouter 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 XiaomiIRouter 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("小米设置");
}
}
建造者模式
( Builder ):建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
例:工地建房子
//抽象的建造者:方法
public abstract class Builder {
//步骤:A->B->C->D
abstract void buildA();//地基
abstract void buildB();//钢筋工程
abstract void buildC();//铺电线
abstract void buildD();//粉刷
//完工:得到产品
abstract Product getProduct();
}
//产品:房子
public class Product {
private String buildA;
private String buildB;
private String buildC;
private String buildD;
public String getBuildA() {
return buildA;
}
public void setBuildA(String buildA) {
this.buildA = buildA;
}
public String getBuildB() {
return buildB;
}
public void setBuildB(String buildB) {
this.buildB = buildB;
}
public String getBuildC() {
return buildC;
}
public void setBuildC(String buildC) {
this.buildC = buildC;
}
public String getBuildD() {
return buildD;
}
public void setBuildD(String buildD) {
this.buildD = buildD;
}
@Override
public String toString() {
return "Product{" +
"buildA='" + buildA + '\'' +
", buildB='" + buildB + '\'' +
", buildC='" + buildC + '\'' +
", buildD='" + buildD + '\'' +
'}';
}
}
定义一个工人类
public class Worker extends Builder{
private Product product;
public Worker() {
product = new Product();
}
@Override
void buildA() {
product.setBuildA("地基");
System.out.println("地基");
}
@Override
void buildB() {
product.setBuildB("钢筋工程");
System.out.println("钢筋工程");
}
@Override
void buildC() {
product.setBuildC("铺电线");
System.out.println("铺电线");
}
@Override
void buildD() {
product.setBuildD("粉刷");
System.out.println("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
定义指挥者:负责指挥工人
//指挥:核心。负责指挥构建一个工程,工程如何构建,由他指挥
public class Director {
public Product build(Builder builder){
//指挥工人按照顺序建房子
builder.buildA();
builder.buildB();
builder.buildC();
builder.buildD();
return builder.getProduct();
}
}
测试:
public class Test {
public static void main(String[] args) {
//指挥
Director director = new Director();
//指挥 具体的工人完成 产品
Product build = director.build(new Worker());
System.out.println(build.toString());
}
}
public abstract class Builder {
abstract Builder buildeA(String msg);//汉堡
abstract Builder buildeB(String msg);//可乐
abstract Builder buildeC(String msg);//薯条
abstract Builder buildeD(String msg);//甜点
abstract Product getProduct();
}
套餐
//产品:套餐
public class Product {
private String BuildA="汉堡";
private String BuildB="可乐";
private String BuildC="薯条";
private String BuildD="甜点";
public String getBuildA() {
return BuildA;
}
public void setBuildA(String buildA) {
BuildA = buildA;
}
public String getBuildB() {
return BuildB;
}
public void setBuildB(String buildB) {
BuildB = buildB;
}
public String getBuildC() {
return BuildC;
}
public void setBuildC(String buildC) {
BuildC = buildC;
}
public String getBuildD() {
return BuildD;
}
public void setBuildD(String buildD) {
BuildD = buildD;
}
@Override
public String toString() {
return "Product{" +
"BuildA='" + BuildA + '\'' +
", BuildB='" + BuildB + '\'' +
", BuildC='" + BuildC + '\'' +
", BuildD='" + BuildD + '\'' +
'}';
}
}
//具体的建造者
public class Worker extends Builder{
private Product product;
public Worker() {
product = new Product();
}
@Override
Builder buildeA(String msg) {
product.setBuildA(msg);
return this;
}
@Override
Builder buildeB(String msg) {
product.setBuildB(msg);
return this;
}
@Override
Builder buildeC(String msg) {
product.setBuildC(msg);
return this;
}
@Override
Builder buildeD(String msg) {
product.setBuildD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
用户可以自己搭配选择
public class Test {
public static void main(String[] args) {
//服务员
Worker worker = new Worker();
//链式编程 : 在原来的基础上,可以*组合了,如果不组合,也有默认的套餐
Product product = worker.buildeA("全家桶").buildeB("雪碧")
.getProduct();
System.out.println(product.toString());
}
}
原型模式
:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
复制拷贝: 第一个方案复制的会跟之前的共用一个时间
/*
1.实现一个接口 Cloneable
2.重写一个方法 clone()
*/
//Video
public class Video implements Cloneable{
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Video() {
}
public Video(String name, Date createTime) {
this.name = name;
this.createTime = createTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", createTime=" + createTime +
'}';
}
}
public class Bilibili {
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象 v1
Date date = new Date();
Video v1 = new Video("狂神说JAVA", date);
System.out.println("v1=>"+v1);
System.out.println("v1=>hash"+v1.hashCode());
//v1 克隆 v2
//Video v2 = new Video("狂神说JAVA", date);
Video v2 = (Video) v1.clone();
System.out.println("v2=>"+v2);
System.out.println("v2=>hash"+v2.hashCode());
}
}
第二个在修改时间的情况下会分隔开
/*
1.实现一个接口 Cloneable
2.重写一个方法 clone()
*/
//Video
public class Video implements Cloneable{
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
//实现深克隆~ 序列化、反序列化
Video v = (Video) obj;
v.createTime = (Date)this.createTime.clone();//将这个对象的属性进行克隆
return obj;
}
public Video() {
}
public Video(String name, Date createTime) {
this.name = name;
this.createTime = createTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", createTime=" + createTime +
'}';
}
}
//Spring Bean:单例模式,原型模式~
// 原型模式 + 工厂模式 ==> new <==> 原型模式
public class Bilibili {
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象 v1
Date date = new Date();
Video v1 = new Video("狂神说JAVA", date);
Video v2 = (Video) v1.clone();
System.out.println("v1=>"+v1);
System.out.println("v2=>"+v2);
System.out.println("======================");
date.setTime(231321312);
System.out.println("v1=>"+v1);
System.out.println("v2=>"+v2);
/*
//原型对象 v1
Date date = new Date();
Video v1 = new Video("狂神说JAVA", date);
System.out.println("v1=>"+v1);
System.out.println("v1=>hash"+v1.hashCode());
//v1 克隆 v2
//Video v2 = new Video("狂神说JAVA", date);
Video v2 = (Video) v1.clone();
System.out.println("v2=>"+v2);
System.out.println("v2=>hash"+v2.hashCode());
*/
}
}
结构型模式
适配器模式
:是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。
//接口转换器的抽象实现
public interface NetToUsb {
//作用:处理请求,网线=>usb
public void handleRequest();
}
//要被适配的类 :网线
public class Adaptee {
public void request(){
System.out.println("连接网线上网");
}
}
//1.继承 (类适配器,单继承)----
//2.组合 (对象适配器,常用)
//真正的适配器~,需要连接USB,连接网线~
public class Adapter extends Adaptee implements NetToUsb{
@Override
public void handleRequest() {
super.request();//可以上网了~
}
}
//1.继承 (类适配器,单继承)
//2.组合 (对象适配器,常用)------
//真正的适配器~,需要连接USB,连接网线~
public class Adapter2 implements NetToUsb{
private Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void handleRequest() {
adaptee.request();//可以上网了~
}
}
//客户端类:想上网,插不上网线~
public class Computer {
//我们的电脑需要连接上转接器才可以上网
public void net(NetToUsb adapter) {
//上网的具体实现~,找一个转接头
adapter.handleRequest();
}
public static void main(String[] args) {
//电脑,网线,适配器~
Computer computer = new Computer();//电脑
Adaptee adaptee = new Adaptee();//网线
Adapter2 adapter = new Adapter2(adaptee);//转接器 (比较完美的实现)
//Adapter adapter = new Adapter();//转接器
computer.net( adapter);
}
}
桥接模式
:是将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(interface)模式。
结构图:
//品牌
public interface Brand {
void info();
}
//苹果
public class Apple implements Brand{
@Override
public void info() {
System.out.print("苹果");
}
}
//联想
public class Lenovo implements Brand{
@Override
public void info() {
System.out.print("联想");
}
}
//抽象的电脑类
public abstract class Computer {
//组合,品牌~
protected Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void info(){
brand.info();//自带品牌
}
}
class Desktop extends Computer{
public Desktop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.println("台式机");
}
}
class Laptop extends Computer{
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.println("笔记本");
}
}
测试类:
public class Test {
public static void main(String[] args) {
//苹果笔记本
Computer computer = new Laptop(new Apple());
computer.info();
//联想台式机
Computer computer2 = new Desktop(new Lenovo());
computer2.info();
}
}
结构:(同理上面的图)
代理模式
为什么要学习代理模式?这就是SpringAOP的底层! 【SpringAOP 和 SpringMVC】
代理模式的分类:
-
静态代理
-
动态代理
1.静态代理
角色分析:
-
抽象角色:一般会使用接口或者抽象类来解决
-
真是角色:被代理的角色
-
代理角色:代理真实角色,代理真实角色后一般会做一些附属操作
-
客户:访问代理对象的人!
代码步骤:
1.接口
//租房
public interface Rent {
public void rent();
}
2.真实角色
//房东
public class Landlord implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
3.代理角色
public class Proxy implements Rent{
private Landlord landlord;
public Proxy() {
}
public Proxy(Landlord landlord) {
this.landlord = landlord;
}
@Override
public void rent() {
seeHouse();
landlord.rent();
hetong();
fee();
}
public void seeHouse(){
System.out.println("中介带你看房");
}
public void fee(){
System.out.println("收中介费");
}
public void hetong(){
System.out.println("签租赁合同");
}
}
4.客户端访问代理角色
public class Client {
public static void main(String[] args) {
//房东要出租房子
Landlord landlord = new Landlord();
//代理,中介帮房东出租房子,但是呢?代理角色一般会有一些附属操作
Proxy proxy = new Proxy(landlord);
//你不用面对房东,直接找中介租房子即可!
proxy.rent();
}
}
代理模式的好处:
-
可以使真是角色的操作更加纯粹!不用去关注一些公共的业务
-
公共的业务也就交给代理角色!实现了业务的分工!
-
公共业务发生拓展的时候,方便集中管理!
缺点:
-
一个真是角色就会产生一个代理角色:代码量会翻倍~ 开发效率会变低~
2.加深理解静态代理
代码:
1.接口
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
2.实现类
//真实对象
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void delete() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("修改了一个用户");
}
@Override
public void query() {
System.out.println("查询了一个用户");
}
//1、改动原有的业务代码,在公司中是大忌!
}
3.代理
public class UserServiceProxy implements UserService{
UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
//日志方法
public void log(String msg){
System.out.println("使用了[Debug]"+msg+"方法");
}
}
4.客户端访问
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}
3.动态代理
-
动态代理和静态代理角色一样
-
动态代理的代理类是动态的,不是我们直接写好的!
-
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
-
基于接口- - - JDK动态代理【我们在这里使用】
-
基于类:cglib
-
Java字节码实现:javasist
-
需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序
动态代理的好处:
-
可以使真是角色的操作更加纯粹!不用去关注一些公共的业务
-
公共的业务也就交给代理角色!实现了业务的分工!
-
公共业务发生拓展的时候,方便集中管理!
-
一个动态代理类代理的是一个接口,一般就是对应的一类业务
-
一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
代码:
1.接口
//租房
public interface Rent {
public void rent();
}
2.真实对象
//房东
public class Landlord implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
3.代理
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是反射机制的实现!
seeHouse();
Object result = method.invoke(rent,args);
return result;
}
public void seeHouse(){
System.out.println("中介带看房子");
}
}
4.客户端访问对象
public class Client {
public static void main(String[] args) {
//真实角色
Landlord landlord = new Landlord();
//代理角色:现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象!
pih.setRent(landlord);
Rent proxy = (Rent) pih.getProxy();//这里的proxy就是动态生成的,我们并没有写!
proxy.rent();
}
}
优化动态代理万能的方法:
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy(){//最后面的this代表实现的接口 InvocationHandler
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//动态代理的本质,就是反射机制的实现!
Object result = method.invoke(target,args);
return result;
}
public void log (String msg){
System.out.println("使用了"+msg+"方法");
}
}
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色,不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);//设置要代理的对象
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.query();
}
}