【Java设计模式】三、

news2024/9/22 17:34:31

文章目录

  • 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{

	@Override
	public String getName(){
		return "美式";
	}
}
public class LatteCoffee extends Coffee{

	@Override
	public 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;
    }
	
	//也可set
	public 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{
	@Override
	public 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;

	@Override
	public CarDoor getCarDoor(){
		carDoor = new CarDoor();
		return carDoor;
	}

	@Override
	public CarFrame getCarFrame(){
		carFrame = new new CarFrame();
		return carFrame;
	}
	
	@Override
	public CarBasePlate getCarBasePlate(){
		carBasePlate = new CarBasePlate();
		return carBasePlate;
	}

	@Override
	public 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();

	@Overrid
	public abstract void buildBasePlate(String basePlate){
		car.setBasePlate(basePlate);
	}
	@Override
	public abstract void buildCarFrame(String carFrame){
		car.setFrame(frame);
	}
	@Override
	public abstract void buildCarDoor(String carDoor){
		car.setDoor(carDoor);
	}
	@Override
	public abstract Car makeCar(){
		return this.car;
	}
	
}

创建一个工程师:

public class Engineer{
	
	private CarBuilder carBuilder;

	//自动注入、构造方法、set方法都行,能完成赋值就行,这里写set
	public 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;  //喜欢做的事
	
	@Override
	protected 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.coloradmin.cn/o/1480952.html

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

相关文章

第四个程序:(a+b)^2+a/c-c^2

(ab)^2a/c-c^2运算出结果 步骤: 第一步: 建立项目; 第二步:添加部件,连线,完成程序 第三步:运行得出结果 视频: (ab)^2ac-c^2

软考-计算题

1.二维矩阵转换成一维矩阵 2.算术表达式: 3.计算完成项目的最少时间:之前和的max(必须之前的所有环节都完成) 松弛时间:最晚开始时间-最早开始时间 最早:之前环节都完成的和的max 最晚:总时间…

2024年经典【自动化面试题】附答案

一、请描述一下自动化测试流程? 自动化测试流程一般可以分为以下七步: 编写自动化测试计划; 设计自动化测试用例; 编写自动化测试框架和脚本; 调试并维护脚本; 无人值守测试; 后期脚本维…

java009 - Java面向对象基础

1、类和对象 1.1 什么是对象 万物皆对象,客观存在的事物皆为对象。 1.2 什么是面向对象 1.3 什么是类 类是对现实生活中一类具有共同属性和行为的事物抽象。 特点: 类是对象的数据类型类是具有相同属性和行为的一组对象的集合 1.4 什么是对象的属…

装饰器模式 详解 设计模式

装饰器模式 它允许你在不改变对象结构的情况下,动态地将新功能附加到对象上。 结构: 抽象组件(Component):定义了原始对象和装饰器对象的公共接口或抽象类,可以是具体组件类的父类或接口。具体组件&…

【c++】stack和queue模拟实现

> 作者简介:დ旧言~,目前大二,现在学习Java,c,c,Python等 > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:能手撕stack和queue模拟 > 毒鸡汤:…

Spring Cloud 构建面向企业的大型分布式微服务快速开发框架+技术栈介绍

分布式架构图 Cloud架构清单 Commonservice(通用服务) 1)清单列表 2)代码结构 Component(通用组件) 1)清单列表 2)代码结构 快速开发管理平台——云架构【系统管理平台】 一…

深度学习-回顾经典AlexNet网络:山高我为峰

深度学习-回顾经典AlexNet网络之山高我为峰 深度学习中,经典网络引领一波又一波的技术革命,从LetNet到当前最火的GPT所用的Transformer,它们把AI技术不断推向高潮。2012年AlexNet大放异彩,它把深度学习技术引领第一个高峰&#x…

MySQL:合并查询语句

1、查询表的数据 t_book表数据 SELECT * FROM db_book.t_book; t_booktype表数据 SELECT * FROM db_book.t_booktype; 提醒: 下面的查询操作的数据来自上图查询表的数据 2. 使用 UNION 查询结果合并,会去掉重复的数据 使用UNION关键字是,数…

linux_day04

大纲:命令,vim,gcc,编译工具,生成代码,调试,库makefile,系统编程 文件系统:文件属性,文件内容,万物皆文件(不在内存中的是文件&#…

新书速览|Python数据科学应用从入门到精通

系统教授数据科学与Python实战,涵盖线性回归、逻辑回归、决策树、随机森林、神经网 本书内容 随着数据存储、数据处理等大数据技术的快速发展,数据科学在各行各业得到广泛的应用。数据清洗、特征工程、数据可视化、数据挖掘与建模等已成为高校师生和职场…

Python学习 问题汇总(None)

None的总结 在Python中,对于一些变量往往需要赋初始值,为了防止初始值与正常值混淆,通常采用置0或置空操作,置0比较简单,置空则是赋NoneNone是一个空值,可以赋给任意类型的变量,起到占位的作用…

【Godot4自学手册】第十七节主人公的攻击和敌人的受伤

本节主要学习主人公是如何向敌人发起进攻的,敌人是如何受伤的,受伤时候动画显示,击退效果等。其原理和上一节内容相同,不过有许多细节需要关注和完善。 一、修改Bug 在本节学习之前,我将要对上一节的代码进行完善&am…

基础小白快速入门Python------>模块的作用和意义

模块, 这个词听起来是如此的高大威猛,以至于萌新小白见了瑟瑟发抖,本草履虫见了都直摇头,好像听上去很难的样子,但是但是,年轻人,请听本少年细细讲述,他只是看起来很难,实…

MySql安全加固:可信IP地址访问控制 设置密码复杂度

MySql安全加固:可信IP地址访问控制 & 设置密码复杂度 1.1 可信IP地址访问控制1.2 设置密码复杂度 💖The Begin💖点点关注,收藏不迷路💖 1.1 可信IP地址访问控制 当您在创建用户时使用’%作为主机部分,…

【爬虫逆向实战 逆向滑块 Python+Node】今天逆向的网站有点嘿嘿,还是仅供学习,别瞎搞

逆向日期:2024.03.01 使用工具:Node.js、Python 加密方法:AES标准算法 文章全程已做去敏处理!!! 【需要做的可联系我】 AES解密处理(直接解密即可)(crypto-js.js 标准算…

大模型生成,Open API调用

大模型是怎么生成结果的 通俗原理 其实,它只是根据上文,猜下一个词(的概率)…… OpenAI 的接口名就叫【completion】,也证明了其只会【生成】的本质。 下面用程序演示【生成下一个字】。你可以自己修改 prompt 试试…

Appium移动端自动化测试-(Java)

目录 环境搭建ADB调试工具adb构成adb工作原理adb常用命令电脑连接多个设备跟模拟器使用adb包名与界面名的概念如何获取包名和界面名文件传输获取app启动时间获取手机日志其他命令 Appium全自动化测试框架(python)冲错了序言 环境搭建Appium客户端安装App…

IDEA切换 Springboot初始化 URL

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 往期热门专栏回顾 专栏…

【矩阵】【方向】【素数】3044 出现频率最高的素数

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 素数 矩阵 方向 LeetCode 3044 出现频率最高的素数 给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格,你可以按以下方式生成数字: 最多有 8 条路径可以选择:东&am…