Java 单例模式与工厂模式介绍
数据库的四大特点:
原子性:不可再分
一致性:同成功,同失败
隔离性:互不影响
持久性:不可逆转
单例模式与工厂模式
1.单例模式
1.1 什么是单例模式:
常用的设计模式,单例对象的类只允许一个实例存在。在程序中多次使用同一个对象且作用相同的时候,为了防止频繁的创造对象,单例模式可以让程序在内存中创建一个对象,所有的调用者都共享这一单例对象
1.2 单例的实现主要通过两个步骤:
1.将该类的构造方法定为私有方法,只有通过该类提供的静态方法来得到该类的唯一实例
2.在该类中提供一个静态方法,调用这个方法类持有的引用不为空就返回这个引用,若为空就创建该类的实例并将该类的实例的引用赋予该类保持的引用
1.3 单例模式类型分为饿汉式和懒汉式
1.饿汉式:在类加载的时候已经创建好单例对象
1>构造器私有化(防止new)
2>类的内部创建对象
3>向外部暴露一个公共的静态方法 getInstance
代码:
class Singleton { //1.构造器私有化,只能在内部new对象 private Singleton(){ } //2.内部实例化 private final static Singleton instance =new Singleton(); //3.提供get方法供外部使用,返回实例对象 public static Singleton getInstance(){ return instance; } }
优点:在类加载时进行实例化操作,避免线程同步问题
缺点:在类加载时进行实例化操作,若未使用,造成内存浪费
2.懒汉式:在使用对象是进行加载
class Singleton{ private Singleton(){ } private static Singleton instance; public static synchronized Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }
效率低,比如当实例创建好之后,此时不会存在任何线程安全问题,但是每次访问仍然要加锁,导致效率低下
什么是工厂模式:
一、概述
工厂模式(Factory Pattern) 是一种 创建型设计模式,用于 封装对象的创建逻辑,避免在代码中直接实例化对象,从而提高代码的 可维护性、扩展性和解耦性。工厂模式的核心思想是:将对象的创建和使用分离,把对象创建逻辑封装在一个工厂类中,从而提高代码的可维护性和可扩展性。
二、工厂模式分类
工厂模式包括 简单工厂模式、工厂方法模式、抽象工厂模式,它们的扩展性和复杂度逐步递进:
三、工厂模式的实现
(一)简单工厂模式(Simple Factory Pattern)
不属于23种设计模式之一。简单工厂模式又叫做:静态 工厂方法模式。简单工厂模式是工厂方法模式的一种特殊实现。
简单工厂模式是工厂模式的基础版本,它定义了一个工厂类来创建产品对象。
-
抽象产品 角色
-
具体产品 角色
-
工厂类 角色
示例1:兵工厂
抽象产品 角色:Weapon
public abstract class Weapon { /** * 所有的武器都可以攻击。 */ public abstract void attack(); }
具体产品 角色:Dagger、Fighter、Tank
public class Dagger extends Weapon{ @Override public void attack() { System.out.println("砍丫的!!!"); } }
public class Fighter extends Weapon{ @Override public void attack() { System.out.println("战斗机抛下小男孩!!!!"); } }
public class Tank extends Weapon{ @Override public void attack() { System.out.println("坦克开炮!!!"); } }
工厂类 角色
public class WeaponFactory { /** * 静态方法。要获取什么产品?就看你传什么参数,传TANK获取坦克,传DAGGER获取匕首,传FIGHTER获取战斗机 * 简单工厂模式中有一个静态方法,所以被称为:静态工厂方法模式。 * @param weaponType * @return */ public static Weapon get(String weaponType){ if ("TANK".equals(weaponType)) { return new Tank(); } else if ("DAGGER".equals(weaponType)) { return new Dagger(); } else if ("FIGHTER".equals(weaponType)) { return new Fighter(); } else { throw new RuntimeException("不支持该武器的生产"); } } }
测试:
public class Test { public static void main(String[] args) { // 需要坦克 // 对于我客户端来说,坦克的生产细节,我不需要关心,我只需要向工厂索要即可。 // 简单工厂模式达到了什么呢?职责分离。客户端不需要关心产品的生产细节。 // 客户端只负责消费。工厂类负责生产。一个负责生产,一个负责消费。生产者和消费者分离了。这就是简单工厂模式的作用。 Weapon tank = WeaponFactory.get("TANK"); tank.attack(); // 需要匕首 Weapon dagger = WeaponFactory.get("DAGGER"); dagger.attack(); // 需要战斗机 Weapon fighter = WeaponFactory.get("FIGHTER"); fighter.attack(); } }
测试结果:
简单工厂模式的缺点
缺点一:假设现在需要扩展一个新的产品,WeaponFactory工厂类的代码是需要修改的,显然违背了OCP原则。
什么是OCP原则:软件实体(类、模块、函数等)应对扩展开放,对修改关闭。即在不修改现有代码的前提下,通过扩展实现新功能。
简单工厂模式每次新增对象类型都要修改工厂类,违背该原则。
缺点二:工厂类的责任比较重大,不能出现任何问题,因为这个工厂类负责所有产品的生产,称为全能类,或者有人把它叫做上帝类。
这个工厂类一旦出问题,整个系统必然全部瘫痪。(不要把所有鸡蛋放到一个篮子里面哦。)
(二)工厂方法模式
工厂方法模式将对象创建延迟到子类,每个具体工厂类负责创建特定类型的产品。
工厂方法模式既保留了简单工厂模式的优点,同时又解决了简单工厂模式的缺点。 工厂方法模式的角色包括:
-
抽象工厂角色
-
具体工厂角色
-
抽象产品角色
-
具体产品角色
示例1:兵工厂
就是把工厂开成专门的坦克制造厂和飞机制造厂,各种厂抽象出一个接口厂
抽象产品角色 Weapon
abstract public class Weapon {
public abstract void attack();
}
具体产品角色 Dagger Gun
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!!!");
}
}
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("开枪射击!!!");
}
}
抽象工厂角色 WeaponFactory
abstract public class WeaponFactory {
/**
* 这个方法不是静态的。是实例方法。
* @return
*/
public abstract Weapon get();
}
具体工厂角色 DaggerFactory GunFactory
public class GunFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Gun();
}
}
public class DaggerFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Dagger();
}
}
Test
public class Test {
public static void main(String[] args) {
WeaponFactory weaponFactory = new DaggerFactory();
Weapon dagger = weaponFactory.get();
dagger.attack();
WeaponFactory weaponFactory1 = new GunFactory();
Weapon gun = weaponFactory1.get();
gun.attack();
}
}
测试结果
如果想扩展一个新的产品,只要新增一个产品类,再新增一个该产品对应的工厂即可,例如新增:战斗机
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("战斗机发射核弹!");
}
}
public class FighterFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Fighter();
}
}
客户端程序:
public class Client {
public static void main(String[] args) {
WeaponFactory factory = new GunFactory();
Weapon weapon = factory.get();
weapon.attack();
WeaponFactory factory1 = new FighterFactory();
Weapon weapon1 = factory1.get();
weapon1.attack();
WeaponFactory factory2 = new DaggerFactory();
Weapon weapon2 = factory2.get();
weapon2.attack();
}
}
执行结果如下:
我们可以看到在进行功能扩展的时候,不需要修改之前的源代码,显然工厂方法模式符合OCP原则。
什么是OCP原则:
软件实体(类、模块、函数等)应对扩展开放,对修改关闭。即在不修改现有代码的前提下,通过扩展实现新功能。
工厂方法模式的优点:
一个调用者想创建一个对象,只要知道其名称就可以了。
扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
屏蔽产品的具体实现,调用者只关心产品的接口。
工厂方法模式的缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
示例2:日志记录器工厂
假设我们需要创建不同类型的日志记录器(文件日志、数据库日志),使用工厂方法模式可以这样设计:
// 日志记录器接口
public interface Logger {
void log(String message);
}
步骤 2:实现具体产品类
// 文件日志记录器
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("文件日志: " + message);
}
}
// 数据库日志记录器
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("数据库日志: " + message);
}
}
步骤 3:定义工厂接口
// 日志记录器工厂接口
public interface LoggerFactory {
Logger createLogger();
}
步骤 4:实现具体工厂类
// 文件日志工厂
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
// 数据库日志工厂
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new DatabaseLogger();
}
}
步骤 5:客户端使用
public class Client {
public static void main(String[] args) {
// 创建文件日志工厂
LoggerFactory fileLoggerFactory = new FileLoggerFactory();
Logger fileLogger = fileLoggerFactory.createLogger();
fileLogger.log("这是文件日志");
// 创建数据库日志工厂
LoggerFactory databaseLoggerFactory = new DatabaseLoggerFactory();
Logger databaseLogger = databaseLoggerFactory.createLogger();
databaseLogger.log("这是数据库日志");
}
}
输出结果:
文件日志: 这是文件日志
数据库日志: 这是数据库日志
(三)抽象工厂模式
抽象工厂模式相对于工厂方法模式来说,就是工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类。
抽象工厂中包含4个角色:
抽象工厂角色
- 抽象工厂角色
- 具体工厂角色
- 抽象产品角色
- 具体产品角色
抽象工厂模式的类图如下:
抽象工厂模式代码如下:
第一部分:武器产品族
public abstract class Weapon {
public abstract void attack();
}
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("开枪射击!");
}
}
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!");
}
}
第二部分:水果产品族
public abstract class Fruit {
/**
* 所有果实都有一个成熟周期。
*/
public abstract void ripeCycle();
}
public class Orange extends Fruit{
@Override
public void ripeCycle() {
System.out.println("橘子的成熟周期是10个月");
}
}
public class Apple extends Fruit{
@Override
public void ripeCycle() {
System.out.println("苹果的成熟周期是8个月");
}
}
第四部分:具体工厂类
public class WeaponFactory extends AbstractFactory{
public Weapon getWeapon(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Gun".equals(type)) {
return new Gun();
} else if ("Dagger".equals(type)) {
return new Dagger();
} else {
throw new RuntimeException("无法生产该武器");
}
}
@Override
public Fruit getFruit(String type) {
return null;
}
}
public class FruitFactory extends AbstractFactory{
@Override
public Weapon getWeapon(String type) {
return null;
}
public Fruit getFruit(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Orange".equals(type)) {
return new Orange();
} else if ("Apple".equals(type)) {
return new Apple();
} else {
throw new RuntimeException("我家果园不产这种水果");
}
}
}
第五部分:客户端程序
public class Client {
public static void main(String[] args) {
// 客户端调用方法时只面向AbstractFactory调用方法。
AbstractFactory factory = new WeaponFactory(); // 注意:这里的new WeaponFactory()可以采用 简单工厂模式 进行隐藏。
Weapon gun = factory.getWeapon("Gun");
Weapon dagger = factory.getWeapon("Dagger");
gun.attack();
dagger.attack();
AbstractFactory factory1 = new FruitFactory(); // 注意:这里的new FruitFactory()可以采用 简单工厂模式 进行隐藏。
Fruit orange = factory1.getFruit("Orange");
Fruit apple = factory1.getFruit("Apple");
orange.ripeCycle();
apple.ripeCycle();
}
}
执行结果:
抽象工厂模式的优缺点:
-
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
-
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在AbstractFactory里加代码,又要在具体的里面加代码。
抽象工厂模式的优缺点:
- 优点:将具体产品创建封装,客户端无需依赖具体产品类。
- 缺点:扩展产品族困难,新增产品需修改抽象工厂接口及所有子类。
Java 中工厂模式的实际应用
示例:数据库连接工厂
// 数据库连接接口
public interface DBConnection {
void connect();
}
// MySQL 连接
public class MySQLConnection implements DBConnection {
@Override
public void connect() {
System.out.println("连接到 MySQL 数据库");
}
}
// Oracle 连接
public class OracleConnection implements DBConnection {
@Override
public void connect() {
System.out.println("连接到 Oracle 数据库");
}
}
// 数据库连接工厂
public class DBConnectionFactory {
public static DBConnection getConnection(String dbType) {
if (dbType == null) {
return null;
}
if (dbType.equalsIgnoreCase("MYSQL")) {
return new MySQLConnection();
} else if (dbType.equalsIgnoreCase("ORACLE")) {
return new OracleConnection();
}
throw new IllegalArgumentException("不支持的数据库类型: " + dbType);
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
DBConnection mysqlConn = DBConnectionFactory.getConnection("MYSQL");
mysqlConn.connect();
DBConnection oracleConn = DBConnectionFactory.getConnection("ORACLE");
oracleConn.connect();
}
}
总结
工厂模式是一种非常实用的创建型设计模式,它将对象的创建和使用分离,提高了代码的可维护性和可扩展性。在实际开发中,可以根据需求选择合适的工厂模式:
简单工厂:适用于创建对象逻辑简单且产品种类较少的场景。
工厂方法:适用于需要扩展性,经常新增产品的场景。
抽象工厂:适用于创建一系列相关产品的场景
工厂模式原文链接:https://blog.csdn.net/m0_73941339/article/details/148344378