创建型模式
day 1-1 1.创建型模式 - ☆☆☆单例模式 - 小明的购物车
题目链接设计模式
什么是单例模式
一个类只有一个实例,并且提供一个全局访问点来访问这个实例
实现:
为什么要使用单例模式
- 全局控制
- 节约资源
- 懒加载
单例设计模式的基本要求
- 私有构造函数:防止外部代码直接创建类的实例
- 私有的静态实例变量:保存该类的唯一实例
- 公有的静态方法:通过公有的静态方法来获取类的实例
单例设计模式的实现
- 饿汉式:实例在类加载的时候就被创建,实现相对简单,但是实例有可能没有使用而造成资源浪费
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
// 私有构造方法,防止外部实例化
}
public static Singleton getInstance() {
return instance;
}
}
- 懒汉式:第一次使用时才创建,多线程情况下多个线程同时调用
getInstance()
方法,导致多个实例被创建,存在线程安全问题
public class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造方法,防止外部实例化
}
// 使用了同步关键字来确保线程安全, 可能会影响性能
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 在懒汉式的基础上使用双重检查锁来提高性能
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
// 私有构造方法,防止外部实例化
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
什么时候使用单例模式
结合单例设计模式的优点来看:
- 资源共享
a. 全局的配置管理器
b. 数据库连接池 - 只有一个实例
a. 缓存实例
b. 线程池 - 懒加载
a.对象创建比较消耗资源,而且可能程序中不一定使用的情况
b.Java的Runntime
类
c.Spring框架的应用上下文ApplicationContext
代码实现
- 饿汉式
// 饿汉式
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
public class Main{
public static void main(String[] args){
ShoppingCartManger cart = ShoppingCartManger.getInstance();
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
String itemName = scanner.next();
int quantity = scanner.nextInt();
// 获取购物车实例并添加商品
cart.addCart(itemName, quantity);
}
// 输出购物车内容
cart.viewCart();
}
}
class ShoppingCartManger{
// 饿汉式模式实现单例
private static final ShoppingCartManger instance = new ShoppingCartManger();
// 购物车存储商品和数量的映射
private Map<String, Integer> cart;
// 私有化构造函数
private ShoppingCartManger(){
cart = new LinkedHashMap<>();
}
// 获取购物车实例
public static ShoppingCartManger getInstance(){
return instance;
}
// 添加商品到购物车
public void addCart(String itemName, int quantity){
cart.put(itemName, cart.getOrDefault(itemName, 0) + quantity);// value值是在原有的基础上累加
}
// 查看购物车
public void viewCart(){
for(Map.Entry<String, Integer> entry : cart.entrySet()){
System.out.println(entry.getKey()+" "+entry.getValue());
}
}
}
- 懒汉式
// 懒汉式
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
public class Main{
public static void main(String[] args){
ShoppingCartManger cart = ShoppingCartManger.getInstance();
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
String itemName = scanner.next();
int quantity = scanner.nextInt();
// 获取购物车实例并添加商品
cart.addCart(itemName, quantity);
}
// 输出购物车内容
cart.viewCart();
}
}
class ShoppingCartManger{
// 饿汉式模式实现单例
private static ShoppingCartManger instance; // 修改一
// 购物车存储商品和数量的映射
private Map<String, Integer> cart;
// 私有化构造函数
private ShoppingCartManger(){
cart = new LinkedHashMap<>();
}
// 获取购物车实例
public static ShoppingCartManger getInstance(){ // 修改二
if(instance == null){
return instance = new ShoppingCartManger();
}else{
return instance;
}
}
// 添加商品到购物车
public void addCart(String itemName, int quantity){
cart.put(itemName, cart.getOrDefault(itemName, 0) + quantity);// value值是在原有的基础上累加
}
// 查看购物车
public void viewCart(){
for(Map.Entry<String, Integer> entry : cart.entrySet()){
System.out.println(entry.getKey()+" "+entry.getValue());
}
}
}
- 懒汉 + 双重锁检查
// 懒汉 + 双重锁检查
// 懒汉式 + 双重锁检查 + 格式检查加强
import java.util.Scanner;
import java.util.ArrayList;
class ShoppingCartManger{
// 购物车管理器的单例变量,使用volatile关键字确保线程安全
private static volatile ShoppingCartManger instance;
//
private static ArrayList<String> productNames = new ArrayList<>();
//
private static ArrayList<Integer> productQuantities = new ArrayList<>();
//
private ShoppingCartManger(){
}
// 获取购物车单例实例的方法,确保线程安全 双重锁检查
public static ShoppingCartManger getInstance(){
if(instance == null){
synchronized(ShoppingCartManger.class){
instance = new ShoppingCartManger();
}
}
return instance;
}
// 添加商品到购物车
public void add(String itemName, int quantity){
productNames.add(itemName);
productQuantities.add(quantity);
System.out.println(itemName + " " + quantity);
}
}
public class Main{
public static void main(String[] args){
ShoppingCartManger cart = ShoppingCartManger.getInstance();
Scanner scanner = new Scanner(System.in);
String inputLine;
// 循环读取用户输入,直到用户输入"exit"
while(scanner.hasNextLine()){
inputLine = scanner.nextLine();
if("exit".equalsIgnoreCase(inputLine)){
break;
}
String[] parts = inputLine.split(" ");
if(parts.length == 2){
String itemName = parts[0];
int quantity;
try{
quantity = Integer.parseInt(parts[1]);
cart.add(itemName, quantity);
}catch (NumberFormatException e){
System.out.println("转换失败,请重新输入");
}
}else{
System.out.println("输入格式不争取,请重新输入");
}
}
scanner.close();
}
}
day 1-2 2.创建型模式 - ☆工厂方法模式 - 积木工厂
简单工厂模式
是一种创建型设计模式,但不属于23种设计模式之一,是一种编程习惯
将产品的创建过程封装在一个工厂类中,主要角色包括如下:
- 抽象产品:描述产品的通用行为
- 具体产品:实现抽象产品接口或者继承抽象产品类
- 工厂类:负责创建产品
优点:简化了客户端操作,客户端可以调用工厂方法来获取具体产品
缺点:不够灵活,如果需要添加新的产品,就需要修改工厂类的代码。
什么是工厂方法模式
引入抽象工厂和具体工厂,每个工厂只负责创建一个具体产品
工厂方法模式包括的角色如下:
- 抽象工厂:一个接口,包含一个抽象的工厂方法(用于创建产品)
- 具体工厂:实现抽象工厂接口,创建具体的产品
- 抽象产品:定义产品的接口
- 具体产品:实现抽象产品的接口,是工厂创建的对象
基本实现
TODO 图 + 代码
应用场景
特点:工厂方法模式每个工厂职责单一,每个工厂只负责一种产品
应用:
- Spring框架中的Bean工厂
- JDBC的Connection工厂
代码实现
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
// 抽象积木接口
interface Block{
void produce();
}
// 具体圆形积木实现
class CircleBlock implements Block{
@Override
public void produce(){
System.out.println("Circle Block");
}
}
// 具体方形积木实现
class SquareBlock implements Block{
@Override
public void produce(){
System.out.println("Square Block");
}
}
// 抽象积木工厂接口
interface BlockFactory{
Block creatBlock();
}
// 具体圆形积木工厂实现
class CircleBlockFactory implements BlockFactory{
@Override
public Block creatBlock(){
return new CircleBlock();
}
}
// 具体方形积木工厂实现
class SquareBlockFactory implements BlockFactory{
@Override
public Block creatBlock(){
return new SquareBlock();
}
}
// 积木工厂系统
class BlockFactorySystem{
private List<Block> blocks = new ArrayList<>();
public void produceBlocks(BlockFactory factory, int quantity){
for(int i = 0; i < quantity; i++){
Block block = factory.creatBlock();
blocks.add(block);
block.produce();
}
}
public List<Block> getBlocks(){
return blocks;
}
}
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
// 创建积木工厂系统
BlockFactorySystem factorySystem = new BlockFactorySystem();
// 获取生成次数
int productionCount = scanner.nextInt();
scanner.nextLine();// 换行
for(int i = 0; i < productionCount; i++){
String[] productionInfo = scanner.nextLine().split(" ");
String blockType = productionInfo[0];
int quantity = Integer.parseInt(productionInfo[1]);
if(blockType.equals("Circle")){
factorySystem.produceBlocks(new CircleBlockFactory(), quantity);
}else if(blockType.equals("Square")){
factorySystem.produceBlocks(new SquareBlockFactory(), quantity);
}
}
}
}
day 1-3 3.创建型模式 - 抽象工厂模式 - 家具工厂
什么是抽象工厂模式
一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
具体结构
主要角色包括:
- 抽象产品接口
- 具体产品类
- 抽象工厂接口
- 具体工厂类
和工厂方法的角色相同
具体实现
TODO:图+代码
应用场景
扩展性差,使用于一系列相关或相互依赖的产品被一起创建的情况
- 创建与不同数据库的连接对象
简单工厂、工厂方法、抽象工厂的区别
简单工厂模式:一个工厂方法创建所有的具体产品
工厂方法模式:一个工厂创建一个具体的产品
抽象工厂模式:一个工厂方法可以创建一类具体产品
本题代码实现
import java.util.Scanner;
// 抽象椅子接口
interface Chair{
void showInfo();
}
// 具体现代椅子实现
class ModernChair implements Chair{
@Override
public void showInfo(){
System.out.println("modern chair");
}
}
// 具体古典风格椅子实现
class ClassicalChair implements Chair{
@Override
public void showInfo(){
System.out.println("classical chair");
}
}
// 抽象沙发接口
interface Sofa{
void displayInfo();
}
// 具体现代风格沙发实现
class ModernSofa implements Sofa{
@Override
public void displayInfo(){
System.out.println("modern sofa");
}
}
// 具体经典风格沙发实现
class ClassicalSofa implements Sofa{
@Override
public void displayInfo(){
System.out.println("classical sofa");
}
}
// 抽象家具工厂接口
interface FurnitureFactory{
Chair createChair();
Sofa createSofa();
}
// 具体现代风格家具工厂实现
class ModernFurnitureFactory implements FurnitureFactory{
@Override
public Chair createChair(){
return new ModernChair();
}
@Override
public Sofa createSofa(){
return new ModernSofa();
}
}
// 具体经典风格家具工厂实现
class ClassicalFurnitureFactory implements FurnitureFactory{
@Override
public Chair createChair(){
return new ClassicalChair();
}
@Override
public Sofa createSofa(){
return new ClassicalSofa();
}
}
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
// 读取订单数量
int N = scanner.nextInt();
// 处理订单
for(int i = 0; i < N; i++){
// 读取家具类型
String furnitureType = scanner.next();
// 创建相应风格的家具装饰品工厂
FurnitureFactory factory = null;
if(furnitureType.equals("modern")){
factory = new ModernFurnitureFactory();
}else if(furnitureType.equals("classical")){
factory = new ClassicalFurnitureFactory();
}
// 根据工厂生产椅子和沙发
Chair chair = factory.createChair();
Sofa sofa = factory.createSofa();
// 输出家具信息
chair.showInfo();
sofa.displayInfo();
}
}
}
day 1-4 4.创建型模式 - ☆建造者模式 - 自行车加工
什么是建造者模式(也称为生成器模式)
需要创建很复杂的对象,将对象的构建过程分为多个步骤
基本结构
- 产品
- 抽象建造者
- 具体建造者
- 指导者
简单实现
TODO 图 + 对应代码
使用场景
优点:
- 解构
- 构建过程可以创建不同的表示
应用: - JUnit中的测试构建器TestBuilder
本题代码实现
import java.util.Scanner;
// 自行车产品
class Bike{
private String frame;
private String tires;
public void setFrame(String frame){
this.frame = frame;
}
public void setTires(String tires){
this.tires = tires;
}
@Override
public String toString(){
return frame + " " + tires;
}
}
// 自行车构建者接口
interface BikeBuilder{
void buildFrame();
void buildTires();
Bike getResult();
}
// 山地自行车构建者
class MountainBikeBuilder implements BikeBuilder{
private Bike bike;
// 静态方法
public MountainBikeBuilder(){
this.bike = new Bike();
}
@Override
public void buildFrame(){
bike.setFrame("Aluminum Frame");
}
@Override
public void buildTires(){
bike.setTires("Knobby Tires");
}
@Override
public Bike getResult(){
return bike;
}
}
// 公路自行车构建者
class RoadBikeBuilder implements BikeBuilder{
private Bike bike;
// 静态方法
public RoadBikeBuilder (){
this.bike = new Bike();
}
@Override
public void buildFrame(){
bike.setFrame("Carbon Frame");
}
@Override
public void buildTires(){
bike.setTires("Slim Tires");
}
@Override
public Bike getResult(){
return bike;
}
}
// 自行车指挥者Director, 负责构建自行车
class BikeDirector{
public Bike construct(BikeBuilder builder){
builder.buildFrame();
builder.buildTires();
return builder.getResult();
}
}
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
// 订单数量
int N = scanner.nextInt();
// 换行
scanner.nextLine();
BikeDirector director = new BikeDirector();
for(int i = 0; i < N; i++){
String bikeType = scanner.nextLine();
BikeBuilder builder;
// 根据需求类型创建不同类型的自行车构建者
if(bikeType.equals("mountain")){
builder = new MountainBikeBuilder();
}else { // 不知道这里使用else if(bikeType.equals("road"))为啥不行
builder = new RoadBikeBuilder();
}
// director负责指导生产产品
Bike bike = director.construct(builder);
System.out.println(bike);
}
}
}
day 1-5 5.创建型模式 - 原型模式 - 矩形原型
什么是原型模式
基于现有的对象创建新的对象,而不是从头开始创建
为什么使用原型模式
一个对象的创建过程比较复杂,降低对象创建的成本
原型模式的基本结构
- 抽象原型接口
Prototype
- 具体原型类
ConcretePrototype
原型模式的基本实现
TODO: 图 + 代码
什么时候实现原型模式
需要考虑到的问题,对象内部成员包含了引用类型的成员变量,深拷贝比较复杂
实际应用的例子:
- Java提供的Object类的clone()方法,实现对象的浅拷贝
- Spring框架的Bean的作用域之一是原型作用域(Prototype Scope)
本题代码实现
import java.util.Scanner;
// 抽象原型类
abstract class Prototype implements Cloneable{
public abstract Prototype clone();
public abstract String getDetails();
// 公用的clone方法
public Prototype clonePrototype(){
try{
return (Prototype)super.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
return null;
}
}
}
// 具体矩形原型类
class RectanglePrototype extends Prototype{
private String color;
private int width;
private int height;
// 构造方法
public RectanglePrototype(String color, int width, int height){
this.color = color;
this.width = width;
this.height = height;
}
// 克隆方法
@Override
public Prototype clone(){
return clonePrototype();
}
// 获取矩形的详细信息
@Override
public String getDetails(){
return "Color: " + color + ", " + "Width: " + width + ", " + "Height: " + height;
}
}
// 客户端程序
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
// 属性信息
String[] input = scanner.nextLine().split(" ");
String color = input[0];
int width = Integer.parseInt(input[1]);
int height = Integer.parseInt(input[2]);
// 创建原型对象
RectanglePrototype originalRectangle = new RectanglePrototype(color, width, height);
int N = scanner.nextInt();
// 创建指定数量的矩形对象并输出信息
for(int i = 0; i < N; i++){
Prototype clonedRectangle = originalRectangle.clone();
System.out.println(clonedRectangle.getDetails());
}
}
}
总结
- 耗时:4h10min