首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,085 阅读
2
类的加载
742 阅读
3
Spring Cloud OAuth2.0
726 阅读
4
SpringBoot自动装配原理
691 阅读
5
集合不安全问题
586 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
FastApi
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
Mybatis
Spring
html5
蘇阿細
累计撰写
389
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
FastApi
页面
统计
关于
搜索到
2
篇与
的结果
2022-08-27
创建者模式-工厂模式
(1)概述以咖啡店点餐系统为例:当需要添加不同类型的咖啡的时候,需要修改原有的代码,违背了开闭原则,此时如果使用工厂来生产不同类型的咖啡,则只需要与工厂产生对接,工厂模式的最大优点即解耦(2)简单工厂模式简单工厂模式不属于GOF的23种经典设计模式,其更像是一种编程习惯结构抽象产品:定义产品的规范,描述产品的主要特性和功能具体产品:实现或继承抽象产品的子类具体工厂:提供创建产品的方法,调用者通过该方法来获取产品实现工厂处理创建对象的细节,一旦有了 SimpleCoffeeFactory 工厂类,CoffeeStore 类中的 orderCoffee() 就变成此对象的客户,后期如果需要 Coffee 对象直接从工厂获取即可,解除了和 Cooffee 实现类的耦合,但同时又产生了新的耦合:CoffeeStore 对象与 SimpleCoffeeFactory 工厂对象,SimpleCoffeeFactory 工厂对象 与 生产的商品对象CoffeeStorepublic class CoffeeStore { public Coffee orderCoffee(String type) { //通过简单工厂生产咖啡 SimpleCoffeeFactory factory = new SimpleCoffeeFactory(); Coffee coffee = factory.createCoffee(type); //加配料 coffee.addSugar(); coffee.addMilk(); return coffee; } }SimpleCoffeeFactorypublic class SimpleCoffeeFactory { public Coffee createCoffee(String type) { //声明coffee类型的变量,根据不同类型创建不同的coffee子类 Coffee coffee = null; if ("american".equals(type)) { coffee = new AmericanCoffee(); } else if ("latte".equals(type)) { coffee = new LatteCoffee(); } else { throw new RuntimeException("该类型的咖啡暂未上架"); } return coffee; } }Coffeepublic abstract class Coffee { /** * 获取咖啡名字 * * @return */ public abstract String getName(); public void addSugar() { System.out.println("加糖"); } public void addMilk() { System.out.println("加奶"); } }AmericanCoffeepublic class AmericanCoffee extends Coffee { @Override public String getName() { return "美式咖啡"; } }LatteCoffeepublic class LatteCoffee extends Coffee { @Override public String getName() { return "拿铁咖啡"; } }Clientpublic class Client { public static void main(String[] args) { CoffeeStore coffeeStore = new CoffeeStore(); Coffee coffee = coffeeStore.orderCoffee("american"); System.out.println(coffee.getName()); } }优缺点封装了创建对象的过程,可以通过参数直接获取对象,把对象的创建与业务逻辑分开,避免了修改客户端代码,如果要添加新的产品则直接修改工厂类增加新产品时需要修改原有的工厂类,违背了开闭原则扩展(静态工厂)public class SimpleCoffeeFactory { public static Coffee createCoffee(String type) { //声明coffee类型的变量,根据不同类型创建不同的coffee子类 Coffee coffee = null; if ("american".equals(type)) { coffee = new AmericanCoffee(); } else if ("latte".equals(type)) { coffee = new LatteCoffee(); } else { throw new RuntimeException("该类型的咖啡暂未上架"); } return coffee; } }(2)工厂方法模式概念定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象,工厂方法使一个产品类的实例化延迟到其工厂的子类结构抽象工厂:提供创建产品的接口,调用者通过它访问具体工厂的方法来创建产品具体工厂:实现抽象工厂中的抽象方法,完成具体产品的创建抽象产品:定义产品的规范,描述产品的主要功能和特性具体产品:实现抽象产品定义的接口,由具体工厂来创建(与具体工厂一一对应)实现工厂方法模式是简单工厂模式的进一步抽象,由于使用了多态,既保持了简单工厂模式的优点,同时也解决了它的缺点抽象工厂CoffeeFactorypublic interface CoffeeFactory { /** * 创建咖啡对象 * * @return */ Coffee createCoffee(); }具体工厂AmericanCoffeeFactorypublic class AmericanCoffeeFactory implements CoffeeFactory { @Override public Coffee createCoffee() { return new AmericanCoffee(); } }LatteCoffeeFactorypublic class LatteCoffeeFactory implements CoffeeFactory { @Override public Coffee createCoffee() { return new LatteCoffee(); } }咖啡店类CoffeeStorepublic class CoffeeStore { private CoffeeFactory factory; public void setFactory(CoffeeFactory factory) { this.factory = factory; } public Coffee orderCoffee() { Coffee coffee = factory.createCoffee(); coffee.addMilk(); coffee.addSugar(); return coffee; } }Coffeepublic abstract class Coffee { /** * 获取咖啡名字 * * @return */ public abstract String getName(); public void addSugar() { System.out.println("加糖"); } public void addMilk() { System.out.println("加奶"); } }AmericanCoffeepublic class AmericanCoffee extends Coffee { @Override public String getName() { return "美式咖啡"; } }LatteCoffeepublic class LatteCoffee extends Coffee { @Override public String getName() { return "拿铁咖啡"; } }Clientpublic class Client { public static void main(String[] args) { //咖啡店 CoffeeStore store = new CoffeeStore(); //咖啡工厂 //AmericanCoffeeFactory factory = new AmericanCoffeeFactory(); LatteCoffeeFactory factory = new LatteCoffeeFactory(); store.setFactory(factory); //点咖啡 Coffee coffee = store.orderCoffee(); System.out.println(coffee.getName()); } }优缺点用户只需要知道具体工厂的名称就能得到需要的产品,无需关心产品的具体创建过程增加新的产品时只需添加具体产品类和对应的工厂类,无须对原工厂进行修改,满足开闭原则每增加一个产品就要增加一个具体产品类和对应的工厂类,增加了系统的复杂度(3)抽象工厂模式概念为访问类提供一个创建一组或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构结构抽象工厂:提供创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建抽象产品:定义产品的规范,描述产品的主要功能和特性(抽象工厂模式具有多个抽象产品)具体产品:实现抽象产品角色所定义的接口,由具体工厂来创建,它与具体工厂之间是多对一的关系实现当咖啡店业务发生变化时,不仅要上架咖啡,还需要上架甜点(提拉米苏、抹茶慕斯),按照工厂方法模式,很容易发生类爆炸的问题;其中:拿铁、美式属于一个产品等级,都是咖啡;提拉米苏、抹茶慕斯属于一个产品等级,都是甜点;拿铁、提拉米苏属于一个产品类别,都是意大利风味;美式、抹茶慕斯属于一个产品类别,都是美式风味可以使用抽象工厂模式来实现:抽象工厂public interface DessertFactory { /** * 生产咖啡 * * @return */ Coffee createCoffee(); /** * 生产甜品 * * @return */ Dessert createDessert(); }具体工厂public class AmericanDessertFactory implements DessertFactory { @Override public Coffee createCoffee() { return new AmericanCoffee(); } @Override public Dessert createDessert() { return new MatchaMousse(); } } public class ItalyDessertFactory implements DessertFactory { @Override public Coffee createCoffee() { return new LatteCoffee(); } @Override public Dessert createDessert() { return new Tiramisu(); } }如果要添加同一个产品族的话,只需添加一个对应的甜品工厂类,满足开闭原则public abstract class Coffee { /** * 获取咖啡名字 * * @return */ public abstract String getName(); public void addSugar() { System.out.println("加糖"); } public void addMilk() { System.out.println("加奶"); } }public abstract class Dessert { /** * 展示 */ public abstract void show(); }public class Tiramisu extends Dessert { @Override public void show() { System.out.println("提拉米苏"); } } public class LatteCoffee extends Coffee { @Override public String getName() { return "拿铁咖啡"; } }public class MatchaMousse extends Dessert { @Override public void show() { System.out.println("抹茶慕斯"); } } public class AmericanCoffee extends Coffee { @Override public String getName() { return "美式咖啡"; } }public class Client { public static void main(String[] args) { //意大利风味甜品工厂 ItalyDessertFactory factory = new ItalyDessertFactory(); //拿铁 Coffee coffee = factory.createCoffee(); //提拉米苏 Dessert dessert = factory.createDessert(); System.out.println(coffee.getName()); dessert.show(); } }优缺点当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象当产品族中需要增加一个新的产品时,所有的工厂类都需要需改使用场景当需要创建的对象是一系列相互关联或相互依赖的产品族时,如生产厂商的电视机、洗衣机、空调等系统中有多个产品族,但每次只使用其中的一个产品族,如某人只喜欢某一品牌的服装系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构,如输入法更换皮肤(4)模式扩展简单工厂 + 配置文件解耦在工厂类中加载配置文件的全类名,并创建对象进行存储,客户端如果需要对象,直接获取即可a. 定义配置文件bean.propertiesamerican=com.sw.设计模式.创建者模式.factory.configFactory.AmericanCoffee latte=com.sw.设计模式.创建者模式.factory.configFactory.LatteCoffeeb. 改进工厂类public class CoffeeFactory { //加载配置文件,获取配置文件中配置的全类名,并创建该类的对象进行存储 //1.定义容器对象存储咖啡 private static HashMap<String, Coffee> map = new HashMap<>(); //2.加载配置文件 static { //创建properties对象 Properties p = new Properties(); //调用load()方法进行加载 InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties"); try { p.load(is); //从p集合中获取全类名并创建对象 for (Object key : p.keySet()) { String className = p.getProperty((String) key); Class<?> clazz = Class.forName(className); Coffee coffee = (Coffee) clazz.newInstance(); //存储 map.put((String) key, coffee); } } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } /** * 根据名称获取对象 * * @param name 名称 * @return */ public static Coffee createCoffee(String name) { return map.get(name); } }使用静态成员变量来存储创建的对象,在静态代码块中读取配置文件并创建对象public class Client { public static void main(String[] args) { Coffee coffee = CoffeeFactory.createCoffee("american"); //美式咖啡 System.out.println(coffee.getName()); System.out.println("============================="); Coffee coffee1 = CoffeeFactory.createCoffee("latte"); //拿铁咖啡 System.out.println(coffee1.getName()); } }
2022年08月27日
36 阅读
0 评论
0 点赞
2022-08-27
创建者模式-单例模式
特点:将对象的创建与使用分离,可以降低系统的耦合度,使用者不需要关注对象的创建细节分为:单例模式、工厂模式、抽象工厂模式、原型模式、建造者模式1. 单例模式单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象单例模式的实现:饿汉式:类一加载就创建该实例对象懒汉式:需要使用时才创建该实例对象(1)饿汉式(静态变量方式)该方式在成员位置声明 Singleton 类型的静态变量,并创建 Singleton 类的对象 instance,instance 对象随着类的加载被创建,如果该类足够大且一直没有被使用的情况下会造成内存的浪费Singletonpublic class Singleton { //1.私有构造方法 private Singleton() { } //2.在本类中创建本类对象 private static Singleton instance = new Singleton(); //3.提供一个公共的访问方式,让外界获取该对象 public static Singleton getInstance() { return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); //true System.out.println(instance == instance1); } }(2)饿汉式(静态代码块方式)该方式在成员位置声明 Singleton 类型的静态变量,而对象的创建是在静态代码块中,也是随着类的加载而被创建,与静态变量方式类似Singletonpublic class Singleton { private Singleton() { } private static Singleton instance; static { instance = new Singleton(); } public static Singleton getInstance() { return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); //true System.out.println(instance == instance1); } }(3)懒汉式(线程不安全)当调用 getInstance() 方法获取 Singleton 类的对象的时候才创建 Singleton 类的对象,这样就实现了懒加载,但在多线程操作时存在线程不安全的问题Singletonpublic class Singleton { private Singleton() { } private static Singleton instance; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); //多线程操作时,存在线程不安全的问题 System.out.println(instance == instance1); } }(4)懒汉式(双重检测锁)使用 volatile 关键字保证可见性和防止指令重排(JVM在实例化对象时会进行优化和指令重排序操作,可能产生空指针)Singletonpublic class Singleton { private Singleton() { } //volatile保证可见性和防止指令重排 private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance == instance1); } }(5)懒汉式(静态内部类)实例由内部类创建,由于JVM在加载外部类的过程中不会加载静态内部类,只有内部类的属性/方法被调用时才会被加载,并初始化其静态属性,其中静态属性由于被 static 修饰,保证只被实例化一次,并且严格保证实例化顺序说明:第一次加载 Singleton 类时不会去初始化 INSTANCE,只有第一次调用 getInstance() 时,虚拟机加载 SingletonHolder 并初始化 INSTANCE ,这样既保证了现成安全,也保证了 Singleton 的唯一性,在没有加任何锁的情况下保证了线程的安全且不造成性能和内存的浪费(双重检测锁方式 和 静态内部类方式可以任选其一)Singlepublic class Singleton { private Singleton() { } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance == instance1); } }(6)枚举方式枚举是线程安全的,且只会被加载一次,注意枚举方式属于饿汉式Singletonpublic enum Singleton { INSTANCE; }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.INSTANCE; Singleton instance1 = Singleton.INSTANCE; //true System.out.println(instance == instance1); } }(7)存在的问题破坏单例模式的方式:序列化和反序列化反射解决方法:序列化和反序列化 - 在单例类中添加 readResolve() 方法,在反序列化时,如果类中定义了这个方法,就返回这个方法的值,反之则创建新的对象反射 - 在单例类的构造方法中通过标志位来判断是否是第一次访问,且在该构造方法中需要加 synchronized 锁,锁该类 synchronized(Singleton.class)
2022年08月27日
46 阅读
0 评论
0 点赞