【Java设计模式】三、

文章目录

  • 0、案例:咖啡屋
  • 1、简单工厂模式 + 静态工厂(不属于23种之列)
  • 2、工厂方法模式
  • 3、抽象工厂模式
  • 4、建造者模式
  • 5、原型设计模式

0、案例:咖啡屋

模拟咖啡店点餐。咖啡有多种,抽象类,子类为各种咖啡。咖啡店类聚合咖啡类。类图如下:

在这里插入图片描述

定义咖啡抽象类:

public abstract class Coffee {//获取咖啡种类名称public abstract String getName();//加奶public void addMilk() {System.out.println("加奶");}//加糖public void addSugar() {System.out.println("加糖");}}

各种咖啡:

public class AmericanCoffee extends Coffee{@Overridepublic String getName(){return "美式";}
}
public class LatteCoffee extends Coffee{@Overridepublic String getName(){return "拿铁";}
}

咖啡屋类,聚合咖啡抽象类:

public class CoffeeStore {public Coffee orderCoffee(String type) {Coffee coffee = null;if("americano".equals(type)) {coffee = new AmericanoCoffee();} else if("latte".equals(type)) {coffee = new LatteCoffee();} else {throw new RuntimeException("店里没这种咖啡");}return coffee;}
}

以上代码的缺陷是咖啡类和 + 咖啡屋内耦合太高。下面用工厂模式解耦合。

1、简单工厂模式 + 静态工厂(不属于23种之列)

即由一个工厂决定创建哪一种产品类型的实例。 包括:

  • 抽象产品(抽象类)
  • 具体产品(子类)
  • 具体工厂(创建产品并提供方法给调用者)

改进上面的咖啡案例,引入工厂类,让咖啡屋不再自己创建咖啡对象,而是直接从工厂获取,类图:

在这里插入图片描述

/*** 咖啡工厂类*/
public class SimpleCoffeeFactory {public Coffee createCoffee(String type) {Coffee coffee = null;if("americano".equals(type)) {coffee = new AmericanoCoffee();} else if("latte".equals(type)) {coffee = new LatteCoffee();}return coffee;}
}
//新的咖啡屋类
public class CoffeeStore {public Coffee orderCoffee(String type) {SimpleCoffeeFactory factory = new SimpleCoffeeFactory();Coffee coffee =  factory.createCoffee(type);//加配料coffee.addMilk();coffee.addsugar();return coffee;}
}

到这儿,有个疑惑,咖啡抽象类或子类变时,SimpleCoffeeFacroty类不还得变?这和直接咖啡屋类有啥区别?不都是改一个类?多此一举?其实不然,如果有一百家咖啡屋,而你没有工厂,那需求变更时你就得改一百次代码,而有了工厂,你只需改工厂一个类就行。本质还是这个工厂类带来了解耦。简单工厂可扩展为静态工厂(即把创建对象的方法改为静态的):

public class SimpleCoffeeFactory {//静态的public static Coffee createCoffee(String type) {Coffee coffee = null;if("americano".equals(type)) {coffee = new AmericanoCoffee();} else if("latte".equals(type)) {coffee = new LatteCoffee();}return coffe;}
}

但这种模式下,工厂类还是得修改,并不符合开闭原则。

2、工厂方法模式

  • 定义一个接口或者一个抽象的工厂类,让它的实现类(也是一个工厂)来决定创建哪一个实例对象。
  • 根据每个工厂不同的方法,来产生不同的所需要的对象

角色有:

  • 抽象工厂:只提供创建产品的接口给外界调用
  • 具体工厂:实现抽象工厂,完成具体产品的创建
  • 抽象产品:咖啡类
  • 具体产品:美式、拿铁

继续完善案例:

在这里插入图片描述

抽象工厂,只提供一个方法:

public interface CoffeeFactory {Coffee createCoffee();   //生产咖啡对象}

具体的工厂类,实现抽象工厂:美式咖啡工厂、拿铁咖啡工厂

//美式咖啡工厂,专门用来生产美式咖啡
public class LatteCoffeeFactory implements CoffeeFactory {public Coffee createCoffee() {return new LatteCoffee();}}//拿铁咖啡工厂,专门用来生产拿铁咖啡
public class AmericanCoffeeFactory implements CoffeeFactory {public Coffee createCoffee() {return new AmericanCoffee();}}

注意现在的咖啡店类:1)、它依赖于抽象,聚合的是抽象工厂对象 2)、创建咖啡店对象,需要set传一个咖啡工厂对象

public class CoffeeStore {private CoffeeFactory factory;//通过构造方法来赋值public CoffeeStore(CoffeeFactory factory) {this.factory = factory;}//也可setpublic void setFactory(CoffeeFactory factory) {this.factory = factory;}public Coffee orderCoffee(String type) {Coffee coffee = factory.createCoffee();   //直接调抽象类的方法,到时是哪个子工厂,就能创建出哪种咖啡//加配料coffee.addMilk();coffee.addsugar();return coffee;}
}

测试类:

public class Client {public static void main(Stirng[] args) {//创建咖啡店对象CoffeeStore store = new CoffeeStore();//创建具体的咖啡工厂CoffeeFactory factory = new AmericanCoffeeFactory();store.setFactory(factory);//点咖啡Coffee coffee = store.orderCoffee();//获取咖啡名称System.out.println(coffee.getName());}
}

此时,再有新品种咖啡进来,只需新增代码NewCoffeeFactory去实现CoffeeFactory,以及新增Coffee的子类NewCoffee。测试类中自然就是:

//创建具体的咖啡工厂
CoffeeFactory factory = new NewCoffeeFactory();
store.setFactory(factory);
//....

以上无须对原有的工厂做任何修改,符合开闭原则,并不会修改之前的代码。而缺点则是每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

3、抽象工厂模式

前面的工厂方法模式,生产的都是相同系列的对象,如Java课程、python课程。抽象工厂模式则是提供创建一系列相关或相互依赖对象的接口。比如生产汽车,将汽车分为车架、车门、底盘等各个零部件进行生产。

public interface CarFactory{//获取车门对象public CarDoor getCarDoor();//获取车架对象public CarFrame getCarFrame();//获取底盘对象public CarBasePlate getCarBasePlate();//制作汽车public void make();
}
//车门工厂
public abstract class CarDoorFactory{public abstract void make();
}
//底盘工厂
public abstract class CarBasePlateFactory{public abstract void make();
}
//车架工厂
public abstract class CarFrameFactory{public abstract void make();
}
//车门
public class CarDoor extends CarDoorFactory{@Overridepublic abstract void make(){System.out.println("制作车门");}
}
//底盘
public class CarBasePlate extends CarBasePlateFactory{public abstract void make(){System.out.println("制作车底盘");}
}
//车架工厂
public class CarFrame extends CarFrameFactory{public abstract void make(){System.out.println("制作车架");}
}
public class Car implements CarFactory{private CarDoor carDoor = null;private CarFrame carFrame = null;private CarBasePlate carBasePlate = null;@Overridepublic CarDoor getCarDoor(){carDoor = new CarDoor();return carDoor;}@Overridepublic CarFrame getCarFrame(){carFrame = new new CarFrame();return carFrame;}@Overridepublic CarBasePlate getCarBasePlate(){carBasePlate = new CarBasePlate();return carBasePlate;}@Overridepublic void make(){carDoor.make();carFrame.make();carBasePlate.make();System.out.print("小汽车制作完成");}
}

测试:

public class Test{public static void mian(STring[] args){Car car  = new Car();car.getCarBasePlate();car.getCarFrame();car.getCarDoor();car.make();}
}

运行:
在这里插入图片描述

4、建造者模式

  • 将复杂的对象的创建 和 属性赋值所分离
  • 建造的过程和细节我们不需要知道,只需要通过构建者去进行操作
@Data
public class Car{private String basePlate;   //车底盘private String frame;	//车架private String door; 	//车门
}
public abstract class Builder{//车底盘public abstract void buildBasePlate(String basePlate);//车架public abstract void buildCarFrame(String carFrame);//车门public abstract void buildCarDoor(String carDoor);//制作车public abstract Car makeCar();
}

写实现类:

public class CarBuilder extends Builder{private Car car = new Car();@Overridpublic abstract void buildBasePlate(String basePlate){car.setBasePlate(basePlate);}@Overridepublic abstract void buildCarFrame(String carFrame){car.setFrame(frame);}@Overridepublic abstract void buildCarDoor(String carDoor){car.setDoor(carDoor);}@Overridepublic abstract Car makeCar(){return this.car;}}

创建一个工程师:

public class Engineer{private CarBuilder carBuilder;//自动注入、构造方法、set方法都行,能完成赋值就行,这里写setpublic void setCarBuilder(CarBuilder carBuilder){this.carBuilder = carBuilder;}public Car mekeCar(String basePlate, String frame, String door){carBuilder.buildBasePlate(basePlate);carBuilder.buildCarFrame(frame);carBuilder.buildCarDoor(door);return carBuilder.makeCar();}
}

测试:

public class Test{public static void mian(STring[] args){Engineer engineer = new Engineer();CarBuilder carBuilder = new CarBuilder();engineer.setCarBuilder(carBuilder);Car car = engineer.makeCar("制作汽车底盘","制作汽车车架","制作汽车车门");System.out.println(car);}
}

运行:

在这里插入图片描述

5、原型设计模式

  • 用于创建重复的对象,能够保证创建对象的性能
  • 是创建对象的最佳方式
@Data
public class Pig{private String name;   //名字private String doSomething;  //喜欢做的事}

现在要表示佩奇一家,正常创建流程如下:

public class Test{public static void mian(STring[] args){Pig peki = new Pig();peki.setName("佩琪");peki.setDoSomething("喜欢吃蛋糕");System.out.println(peki);Pig george = new Pig();george.setName("乔治");george.setDoSomething("喜欢睡觉");System.out.println(george);Pig pigDad = new Pig();pigDad.setName("猪爸爸");pigDad.setDoSomething("喜欢开车");System.out.println(pigDad);Pig pigMum = new Pig();pigMum.setName("猪妈妈");pigMum.setDoSomething("喜欢做饭");System.out.println(pigMum);}
}

运行:

在这里插入图片描述

采用原型设计模式后:实体类实现Cloneable接口

@Data
public class Pig implements Cloneable{public Pig() {System.out.println("小猪被初始化了...");}private String name;   //名字private String doSomething;  //喜欢做的事@Overrideprotected Object clone() throws CloneNotSupportedException{return super.clone();}
}

再次创建佩奇一家:

public class Test{public static void mian(STring[] args){Pig peki = new Pig();    //先new一个peki.setName("佩琪");peki.setDoSomething("喜欢吃蛋糕");System.out.println(peki);Pig george = (Pig) peki.clone();    //后面就克隆george.setName("乔治");    //如果这里不赋值,那克隆出来的属性和克隆样本一样george.setDoSomething("喜欢睡觉");System.out.println(george);Pig pigDad = (Pig) peki.clone() ;pigDad.setName("猪爸爸");pigDad.setDoSomething("喜欢开车");System.out.println(pigDad);Pig pigMum = (Pig) peki.clone() ;pigMum.setName("猪妈妈");pigMum.setDoSomething("喜欢做饭");System.out.println(pigMum);}
}

运行:

在这里插入图片描述

发现构造方法只被调用了一次,且出来的也照样是不同的对象。因此,当对象属性很多,而又要创建大量这种对象时,就可以用原型设计模式。该模式产生的对象,虽然都是不同的对象,单如果不重新赋值,属性却是与克隆样本保持一致的,即使是一个新的对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/709421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2.29作业

T课上实现通信代码总结&#xff1a; 程序代码&#xff1a; TCPSER.c #include<myhead.h> #define SER_IP "192.168.244.140" //服务器IP #define SER_PORT 9999 //服务器端口号 int main(int argc, const char *argv[]) {//1.创建用于监…

为什么猫咪挑食不吃猫粮?适口性好、普口性价的主食冻干推荐

现代养猫人士往往把自家的小猫看作是生活中的小宝贝&#xff0c;十分宠爱。最令人头疼的就是猫咪挑食不吃猫粮&#xff0c;为什么猫咪挑食不吃猫粮&#xff1f;猫咪挑食应该怎么办&#xff1f;今天为大家分享一个既不让咱宝贝猫咪受罪又可以改善猫咪挑食的方法。 一、为什么猫咪…

深入理解nginx的https sni机制

目录 1. 概述2. 初识sni3. nginx的ssl证书配置指令3.1 ssl_certificate3.2 ssl_certificate_key3.3 ssl_password_file4. nginx源码分析4.1 给ssl上下文的初始化4.2 连接初始化4.3 处理sni回调4.2 动态证书的加载5. 总结阅读姊妹篇: 深入理解nginx的https alpn机制 1. 概述 SN…

Vue+SpringBoot打造音乐偏好度推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 音乐档案模块2.1.2 我的喜好模块2.1.3 每日推荐模块2.1.4 通知公告模块 2.2 用例图设计2.3 实体类设计2.4 数据库设计 三、系统展示3.1 登录注册3.2 音乐档案模块3.3 音乐每日推荐模块3.4 通知公告模…

外包干了6个月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了重庆一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

Dockerfile(1) - FROM 指令详解

FROM 指明当前的镜像基于哪个镜像构建dockerfile 必须以 FROM 开头&#xff0c;除了 ARG 命令可以在 FROM 前面 FROM [--platform<platform>] <image> [AS <name>]FROM [--platform<platform>] <image>[:<tag>] [AS <name>]FROM […

Java+SpringBoot+Vue+MySQL:员工健康管理技术新组合

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

TCP的三次握手和四次挥手 | 查看网络状态

三次握手和四次挥手是在计算机网络中用于建立和终止TCP连接的协议。这两个过程是TCP协议的重要组成部分&#xff0c;确保数据的可靠传输。 三次握手指的是在客户端和服务器之间建立连接时的步骤。具体流程如下&#xff1a; 客户端向服务器发送一个连接请求报文段&#xff08;…

Git教程-Git的基本使用

Git是一个强大的分布式版本控制系统&#xff0c;它不仅用于跟踪代码的变化&#xff0c;还能够协调多个开发者之间的工作。在软件开发过程中&#xff0c;Git被广泛应用于协作开发、版本管理和代码追踪等方面。以下是一个详细的Git教程&#xff0c;我们将深入探讨Git的基本概念和…

数据结构——lesson4带头双向循环链表实现

前言✨✨ &#x1f4a5;个人主页&#xff1a;大耳朵土土垚-CSDN博客 &#x1f4a5; 所属专栏&#xff1a;数据结构学习笔记​​​​​​ &#x1f4a5;双链表与单链表的区分&#xff1a;单链表介绍与实现 &#x1f4a5;对于malloc函数有疑问的:动态内存函数介绍 感谢大家的观看…

tomcat安装步骤流程

安装tomcat是基于安装java的基础上的 JAVA 举例说明&#xff1a; 关闭防火墙 下载java [rootlocalhost ~]#yum install java -y rootlocalhost ~]#yum install epel-release.noarch -y [rootlocalhost ~]#yum provides */javac [rootlocalhost data]#yum install java-1.8.0-o…

6.1 deeplabv3+的pth模型转换为rknn模型

和yolov5的pth模型转换为rknn模型类似&#xff0c;deeplabv3的pth模型转为rknn模型的步骤是&#xff1a; pth------>onnx-------->rknn 1.pth转为onnx 代码如下&#xff1a; #!/usr/bin/env python3 # -*- coding: utf-8 -*- # by [jackhanyuan](https://github.com/…

实现一个线程安全的单例模式

单例模式 单例模式能保证某个类在程序中只存在唯⼀⼀份实例,⽽不会创建出多个实例 某个类,在一个类,只应该创建出一个实例,使用单例模式,就可以对咱们的代码进行一个更严格的校验和检查 单例模式具体的实现⽅式有很多.最常⻅的是"饿汉"和"懒汉"两种单例…

DevEco Studio下载与安装(Windows)

下载地址&#xff1a; HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 安装时直接点击 next 即可。 运⾏已安装的DevEco Studio&#xff0c;⾸次使⽤&#xff0c;请选择Do not import settings&#xff0c;单击OK。 1.安装Node.js 如果本地有下载&#xff0c;可以…

前端JS 时间复杂度和空间复杂度

时间复杂度 BigO 算法的时间复杂度通常用大 O 符号表述&#xff0c;定义为 T(n) O(f(n)) 实际就是计算当一个一个问题量级&#xff08;n&#xff09;增加的时候&#xff0c;时间T增加的一个趋势 T(n)&#xff1a;时间的复杂度&#xff0c;也就相当于所消耗的时长 O&#xff1…

乐吾乐Web可视化RTSP播放

背景 乐吾乐致力于物联网和智能制造等场景的Web可视化平台和解决方案&#xff0c;其中摄像头播放必不可少。 当前国内摄像头都以RTSP协议为主&#xff0c;而HTML不能直接读取RTSP协议&#xff0c;因此需要一个转流服务。乐吾乐Web可视化播放RTSP也是如此&#xff1a; RTSP协…

理解计算着色器中glsl语言的内置变量

概要 本文通过示例的方式&#xff0c;着重解释以下几个内置变量&#xff1a; gl_WorkGroupSizegl_NumWorkGroupsgl_LocalInvocationIDgl_WorkGroupIDgl_GlobalInvocationID 基本概念 局部工作组与工作项 一个3x2x1的局部工作组示例如下&#xff0c;每个小篮格子表示一个工作项…

Vulnhub靶机:basic_pentesting_1

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.4&#xff09; 靶机&#xff1a;basic_pentesting_1&#xff08;10.0.2.6&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/en…

TCP缓存

TCP缓存是指TCP协议在数据传输过程中使用的一种机制&#xff0c;用于临时存储和管理数据包。它主要有三个作用&#xff1a;提高网络性能、保证数据的可靠性和实现流量控制。 首先&#xff0c;TCP缓存可以提高网络性能。当发送端发送数据时&#xff0c;TCP协议会将数据分割成若…

如何实现无公网ip远程访问本地安卓Termux部署的MySQL数据库【内网穿透】

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备&#xff0c;尽管最初并非设计为服务器&#xff0c;但是随着技术的进步我们可以将Android配置为生产力工具&#xff0c;变成一个随身…