首页 文章 精选 留言 我的

精选列表

搜索[Java],共10000篇文章
优秀的个人博客,低调大师

Java描述设计模式(06):建造者模式

本文源码:GitHub·点这里 || GitEE·点这里 一、生活场景 基于建造者模式,描述软件开发的流程。 1、代码实现 /** * 基于建造者模式描述软件开发 */ public class C01_InScene { public static void main(String[] args) { BuilderSoft builderSoft = new SoftImpl () ; ProjectManager manager = new ProjectManager(builderSoft) ; manager.createSoft(); } } /** * 手机软件产品开发 */ class MobileSoft { // 设计 private String design ; // 架构 private String frame ; // 开发 private String develop ; // 上线 private String online ; // 省略 GET SET 方法 } /** * 手机软件流程抽象类 */ abstract class BuilderSoft { // 前期工作 public abstract void earlyWork () ; // 中期工作 public abstract void midWork () ; // 后期工作 public abstract void lateWork () ; // 手机软件完成 public abstract MobileSoft builderSoft () ; } /** * 手机软件具体实现 */ class SoftImpl extends BuilderSoft { private MobileSoft mobileSoft = new MobileSoft(); @Override public void earlyWork() { System.out.println("软件前期设计..."); } @Override public void midWork() { System.out.println("软件中期架构..."); System.out.println("软件中期开发..."); } @Override public void lateWork() { System.out.println("软件后期上线..."); } @Override public MobileSoft builderSoft() { return mobileSoft ; } } /** * 项目经理:把控项目进度 */ class ProjectManager { private BuilderSoft builderSoft ; ProjectManager (BuilderSoft builderSoft){ this.builderSoft = builderSoft ; } // 统筹项目周期 public void createSoft (){ builderSoft.earlyWork(); builderSoft.midWork(); builderSoft.lateWork(); // MobileSoft mobileSoft = builderSoft.builderSoft() ; // return mobileSoft ; } } 2、代码结构图 二、建造者模式 1、基础概念 建造模式是对象的创建模式。建造模式可以将一个产品的内部属性描述与产品的生产过程分割,从而可以使一个建造过程生成具有不同的内部表象的产品对象。也就是使用一个中介对象封装一系列的对象交互,使其各个对象不需要显示的相互调用,而且可以单独的改变对象之间的交互。 2、核心角色 1)、抽象建造者(Builder)角色 给出一个抽象接口,以规范产品对象的各个组成成分的建造。模式中直接创建产品对象的是具体建造者角色。 2)、具体建造者(ConcreteBuilder)角色 完成的任务包括:1.实现抽象建造者Builder所声明的接口,给出完成创建产品实例的操作。2.在建造完成后,提供产品的实例。 3)、导演者(Director)角色 担任这个角色的类调用具体建造者角色以创建产品对象。 4)、产品(Product)角色 产品便是建造的对象。一般来说,一个系统中会有多个产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。 3、模式图解 4、源码实现 /** * 建造者模式代码 */ public class C02_Builder { public static void main(String[] args) { Builder builder = new ConcreteBuilder(); Director director = new Director(builder); director.construct(); Product product = builder.builderProduct(); System.out.println(product.getAct1()); System.out.println(product.getAct2()); } } /** * 产品类 */ class Product { /*定义一些产品的操作*/ private String act1; private String act2; public String getAct1() { return act1; } public void setAct1(String act1) { this.act1 = act1; } public String getAct2() { return act2; } public void setAct2(String act2) { this.act2 = act2; } } /** * Builder 抽象建造者类 */ abstract class Builder{ public abstract void builderact1(); public abstract void builderact2(); public abstract Product builderProduct(); } /** * 具体建造者类 */ class ConcreteBuilder extends Builder{ private Product product = new Product(); @Override public void builderact1() { product.setAct1("操作一:执行..."); } @Override public void builderact2() { product.setAct2("操作二:执行..."); } @Override public Product builderProduct() { return product; } } /** * Director 导演者类 */ class Director{ /*使用建造者抽象类*/ private Builder builder; Director(Builder builder){ this.builder = builder; } /*负责调用各个建造方法*/ public void construct(){ builder.builderact1(); builder.builderact2(); } } 三、实际应用 1、JDK中应用 分析 1)、Appendable定义多个append() 抽象方法,抽象建造者。 2)、AbstractStringBuilder实现Appendable接口,已经作为了建造者,只是抽象类无法实例化。 3)、StringBuilder继承AbstractStringBuilder,即作为具体建造者,也作为指挥者。 2、Spring中应用 源码实现 // 系列方法 public BeanDefinitionBuilder setParentName(String parentName); public BeanDefinitionBuilder setFactoryMethod(String factoryMethod); public BeanDefinitionBuilder setFactoryMethodOnBean(String factoryMethod, String factoryBean); public BeanDefinitionBuilder addConstructorArgValue(@Nullable Object value); public BeanDefinitionBuilder addConstructorArgReference(String beanName); public BeanDefinitionBuilder addPropertyValue(String name, @Nullable Object value); // 构建Bean public AbstractBeanDefinition getRawBeanDefinition() { return this.beanDefinition; } public AbstractBeanDefinition getBeanDefinition() { this.beanDefinition.validate(); return this.beanDefinition; } 上面两处建造者模式的实际应用,都有点形散而神不散的感觉。 四、优缺点分析 优点:减少类之间的相互依赖,降低耦合度。 缺点:ConcreateBuilder变得臃肿庞大,逻辑复杂。 五、源代码地址 GitHub·地址 https://github.com/cicadasmile/model-arithmetic-parent GitEE·地址 https://gitee.com/cicadasmile/model-arithmetic-parent

优秀的个人博客,低调大师

Java描述设计模式(04):抽象工厂模式

GitHub地址:https://github.com/cicadasmile/model-arithmetic-parent 一、抽象工厂模式 1、生活场景 汽车生产根据用户选择的汽车类型,指定不同的工厂进行生产,选择红旗轿车,就要使用中国工厂,选择奥迪轿车,就要使用德国工厂。 2、抽象工厂模式 1) 抽象工厂模式:定义了一个interface用于创建相关对象或相互依赖的对象,而无需指明具体的类;2) 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合;3) 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。4) 将工厂抽象成两层,AbstractFactory(抽象工厂) 和 具体实现的工厂子类,方便程序扩展。 3、代码UML图 4、源代码实现 /** * 抽象工厂模式 */ public class C01_AbstractFactory { public static void main(String[] args) { CarProductFactory factory = new ChinaCarFactory() ; factory.getCar("hq") ; factory = new GermanyCarFactory () ; factory.getCar("ad") ; } } // 汽车生产抽象工厂 interface CarProductFactory { CarProduct getCar (String type) ; } // 中国汽车工厂 class ChinaCarFactory implements CarProductFactory { @Override public CarProduct getCar(String type) { CarProduct product = null ; if ("hq".equals(type)){ product = new HQCar() ; product.name="红旗一号" ; product.date="1999-09-19" ; product.material(); product.origin(); } else if ("df".equals(type)){ product = new DFCar() ; product.name="东风一号" ; product.date="2019-09-19" ; product.material(); product.origin(); } return product ; } } // 德国汽车工厂 class GermanyCarFactory implements CarProductFactory { @Override public CarProduct getCar(String type) { CarProduct product = null ; if ("ad".equals(type)){ product = new ADCar() ; product.name="奥迪A8" ; product.date="2017-09-19" ; product.material(); product.origin(); } else if ("bm".equals(type)){ product = new BMCar() ; product.name="宝马X8" ; product.date="2018-09-19" ; product.material(); product.origin(); } return product ; } } // 汽车生产抽象类 abstract class CarProduct { /** * 汽车名称 */ protected String name ; /** * 生产日期 */ protected String date ; /** * 材料 */ abstract void material () ; /** * 产地 */ abstract void origin () ; } // 红旗车 class HQCar extends CarProduct { @Override void material() { System.out.println(super.name+"材料..."); } @Override void origin() { System.out.println(super.date+":"+super.name+"在中国北京生产"); } } // 东风车 class DFCar extends CarProduct { @Override void material() { System.out.println(super.name+"材料..."); } @Override void origin() { System.out.println(super.date+":"+super.name+"在中国南京生产"); } } // 奥迪车 class ADCar extends CarProduct { @Override void material() { System.out.println(super.name+"材料..."); } @Override void origin() { System.out.println(super.date+":"+super.name+"在德国柏林生产"); } } // 宝马车 class BMCar extends CarProduct { @Override void material() { System.out.println(super.name+"材料..."); } @Override void origin() { System.out.println(super.date+":"+super.name+"在德国慕尼黑生产"); } } 二、Spring框架应用 1、场景描述 Spring框架中获取配置文件中Bean的多种方式。 2、核心配置 <bean id="carBean" class="com.model.design.spring.node04.abstractFactory.CarBean"> <property name="name" value="中国红旗" /> </bean> <bean id="carBean1" class="com.model.design.spring.node04.abstractFactory.CarBean"> <property name="name" value="德国奥迪" /> </bean> 3、测试文件 这里使用了两种方式获取。 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:/spring/spring-abstract-factory.xml"}) public class SpringTest { @Resource private BeanFactory beanFactory ; @Test public void test01 (){ CarBean carBean = (CarBean)beanFactory.getBean("carBean") ; System.out.println(carBean.getName()); } @Test public void test02 (){ ApplicationContext context01 = new ClassPathXmlApplicationContext( "/spring/spring-abstract-factory.xml"); CarBean carBean = (CarBean)context01.getBean("carBean1") ; System.out.println(carBean.getName()); } } 4、结构分析 抽象工厂封装对象的创建。在Spring中,通过实现BeanFactory。可以从Spring的各种容器获取bean。根据Bean的配置,getBean方法可以返回不同类型的对象(单例作用域)或初始化新的对象(原型作用域)。在BeanFactory的实现中,我们可以区分:ClassPathXmlApplicationContext,XmlWebApplicationContext等。 三、工厂模式小结 三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式),工厂模式的核心用意将实例化对象的代码封装起来,放到工厂类中统一管理和维护,完成代码依赖关系的解耦。从而提高程序的可扩展性和维护性。 四、源代码地址 GitHub地址:知了一笑 https://github.com/cicadasmile/model-arithmetic-parent 码云地址:知了一笑 https://gitee.com/cicadasmile/model-arithmetic-parent

优秀的个人博客,低调大师

Java描述设计模式(02):简单工厂模式

一、生活场景简介 1、引入场景 订餐流程简单描述 1)、食品抽象类,规定食品的基础属性操作 2)、鱼类,鸡肉类食品类扩展 3)、订餐流程类,根据食品名称,加工指定类型食品 4)、模拟客户端预定操作 2、源代码实现 1)、关系图谱 2)、代码实现 /** * 简单工厂模式引入场景 */ public class C01_InScene { public static void main(String[] args) { OrderFood1 orderFood = new OrderFood1() ; orderFood.orderFood("fish") ; orderFood.orderFood("chicken") ; } } /** * 订餐流程 */ class OrderFood1 { public Food1 orderFood (String foodName){ Food1 food1 = null ; if (foodName.equals("fish")){ food1 = new FishFood1() ; food1.setName("黑鱼"); } else if (foodName.equals("chicken")){ food1 = new ChickenFood1() ; food1.setName("土鸡"); } if (food1 != null){ food1.foodMaterial(); food1.cookFood(); return food1 ; } else { return null ; } } } /** * 食物抽象类 */ abstract class Food1 { protected String name ; public abstract void foodMaterial () ; public void cookFood (){ System.out.println("食品烹饪:" + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } } /** * 材料:黑鱼一条 */ class FishFood1 extends Food1 { @Override public void foodMaterial() { System.out.println("材料:黑鱼一条"); } } /** * 材料:土鸡一号 */ class ChickenFood1 extends Food1 { @Override public void foodMaterial() { System.out.println("材料:土鸡一号"); } } 3、缺点分析 1)、OCP原则:软件实体,如类、模块和函数,应当对扩展开放,但对修改关闭。2)、违反设计模式的OCP原则,新增食品类不方便扩展,代码改动较大。 二、简单工厂模式 1、基本概念 简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,是由一个工厂对象决定创建出哪个类的对象实例。 2、代码逻辑 1)、关系图谱 2)、代码实现 /** * 简单工厂模式 */ public class C02_SimpleFactory { public static void main(String[] args) { OrderFood2 orderFood2 = new OrderFood2() ; orderFood2.orderFood("chicken"); } } class OrderFood2 { private SimpleFactory simpleFactory = new SimpleFactory() ; public void orderFood (String foodName){ simpleFactory.orderFood(foodName) ; } } /** * 简单工厂类:封装食品的生产流程 */ class SimpleFactory { public Food2 orderFood (String foodName){ Food2 food2 = null ; if (foodName.equals("fish")){ food2 = new FishFood2() ; food2.setName("黑鱼"); } else if (foodName.equals("chicken")){ food2 = new ChickenFood2() ; food2.setName("土鸡"); } if (food2 != null){ food2.foodMaterial(); food2.cookFood(); return food2 ; } else { return null ; } } } abstract class Food2 { protected String name ; public abstract void foodMaterial () ; public void cookFood (){ System.out.println("食品烹饪:" + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } } class FishFood2 extends Food2 { @Override public void foodMaterial() { System.out.println("材料:黑鱼一条"); } } class ChickenFood2 extends Food2 { @Override public void foodMaterial() { System.out.println("材料:土鸡一号"); } } 3、优缺点分析 1)、优点总结 该模式的核心是工厂类。这个类含有必要的逻辑判断, 可以决定在什么时候创建哪一个登录验证类的实例, 而调用者则可以免除直接创建对象的责任。简单工厂模式通过这种做法实现了对责任的分割, 当系统引入新的登录方式的时候无需修改调用者。 2)、缺点总结 这个工厂类集中了所有的创建逻辑,当有复杂的多层次等级结构时, 所有的业务逻辑都在这个工厂类中实现。什么时候它不能工作了, 整个系统都会受到影响。 三、源代码地址 GitHub地址:知了一笑 https://github.com/cicadasmile/model-arithmetic-parent 码云地址:知了一笑 https://gitee.com/cicadasmile/model-arithmetic-parent

优秀的个人博客,低调大师

Java描述设计模式(01):单例模式

一、单例模式 1、概念图解 单例设计模式定义:确保这个类只有一个实例,并且自动的实例化向系统提供这个对象。 2、样例代码 package com.model.test; public class Singleton { // 使用静态变量记录唯一实例 private static Singleton singleton = null; private Singleton (){} public static Singleton getInstance (){ if (singleton == null){ singleton = new Singleton() ; } return singleton ; } public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance() ; Singleton singleton2 = Singleton.getInstance() ; /** * com.model.test.Singleton@15db9742 * com.model.test.Singleton@15db9742 */ System.out.println(singleton1); System.out.println(singleton2); } } Singleton称为单例类,构造函数使用private修饰,确保系统中只能产生一个实例,并且自动生成的。上面代码也就是所谓的懒汉式加载:只有到使用该对象的时候才来创建,意思饿了才来做饭吃。 二、线程安全问题 在上面的代码中存在一个很明显的线程安全问题,当有多条线程来请求对象实例的时候,因为对象的创建是需要时间的,假设A线程进来判断singleton == null,就会进入对象的创建过程,这时如果同时在过来几条线程,那么他们都会得到一个对象实例,这个就是所谓的线程安全问题。 1、同步控制方式 package com.model.test; public class Singleton { // 使用静态变量记录唯一实例 private static Singleton singleton = null; private Singleton (){} public static synchronized Singleton getInstance (){ if (singleton == null){ singleton = new Singleton() ; } return singleton ; } } 这样操作会影响系统性能 2、饿汉式加载 public class Singleton { // 使用静态变量记录唯一实例 private static Singleton singleton = new Singleton(); private Singleton (){} public static Singleton getInstance (){ return singleton ; } } 这里先把对象创建出来,有需要直接使用; 3、双重检查 public class Singleton { // 使用静态变量记录唯一实例 // volatile可以确保当singleton被初始化后,多线程才可以正确处理 // 被volatile修饰的变量的值,将不会被本地线程缓存 // 对该变量读写都是直接操作共享内存,确保多个线程能正确的处理该变量。 private static volatile Singleton singleton = null ; private Singleton (){} public static Singleton getInstance (){ // 如果实例不存在,则进入同步区 if (singleton == null){ // 只有第一次才会彻底执行这里面的代码 synchronized (Singleton.class) { if (singleton == null){ singleton = new Singleton() ; } } } return singleton ; } } 4、枚举方式 package com.model.design.base.node01.singleton; import org.junit.Test; /** * 类级内部类里面创建对象实例 */ public class C06_Singleton { @Test public void test01 (){ SingletonDemo INSTANCE1 = SingletonDemo.INSTANCE ; SingletonDemo INSTANCE2 = SingletonDemo.INSTANCE ; System.out.println(INSTANCE1 == INSTANCE2); INSTANCE1.info(); INSTANCE2.info(); } } enum SingletonDemo { INSTANCE ; public void info (){ System.out.println("枚举方式实现单例"); } } 三、延迟类初始化 1、基础概念 1)、类级内部类 简单点说,类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。 类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。 类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。 类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。 2)、多线程缺省同步锁 在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地执行了同步,这些情况下就不用自己再来进行同步控制了。这些情况包括: 1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时 2.访问final字段时 3.在创建线程之前创建对象时 4.线程可以看见它将要处理的对象时 2、实现方式 要想很简单地实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程的安全性。比如前面的饿汉式实现方式,在类装载的时候就初始化对象,不管是否需要,存在一定的空间浪费。一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例。这样一来,只要不使用到这个类级内部类,那就不会创建对象实例,从而同时实现延迟加载和线程安全。 public class LazySingleton { /** * 类级内部类 */ private static class SingletonHolder { private static LazySingleton lazySingleton = new LazySingleton() ; } public static LazySingleton getInstance (){ return SingletonHolder.lazySingleton ; } public static void main(String[] args) { LazySingleton lazySingleton1 = LazySingleton.getInstance() ; LazySingleton lazySingleton2 = LazySingleton.getInstance() ; /** * com.model.test.LazySingleton@15db9742 * com.model.test.LazySingleton@15db9742 */ System.out.println(lazySingleton1+";;"+lazySingleton2); } } 四、JDK源码单例模式 Runtime单例实现源码。 1、案例演示 /** * JDK 单例模式分析 */ public class C07_Singleton { public static void main(String[] args) { Runtime runtime1 = Runtime.getRuntime() ; Runtime runtime2 = Runtime.getRuntime() ; /* * 1229416514 * 1229416514 */ System.out.println(runtime1.hashCode()); System.out.println(runtime2.hashCode()); } } 2、源代码分析 public class Runtime { private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime() { return currentRuntime; } private Runtime() {} } 基于饿汉模式实现的单例模式。 五、Spring框架中应用 1、创建测试类 public class UserBean { } 2、Spring配置文件 <!-- 单例Bean --> <bean id="user" class="com.model.design.spring.node01.singleton.UserBean" /> 3、测试读取Bean对象 package com.model.design.spring.node01.singleton; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Spring框架中单例模式 */ public class S01_Singleton { @Test public void test01 (){ ApplicationContext context01 = new ClassPathXmlApplicationContext("/spring/spring-context.xml"); ApplicationContext context02 = new ClassPathXmlApplicationContext("/spring/spring-context.xml"); UserBean user01 = (UserBean)context01.getBean("user") ; UserBean user02 = (UserBean)context01.getBean("user") ; UserBean user03 = (UserBean)context02.getBean("user") ; // com.model.design.spring.node01.singleton.UserBean@364841 System.out.println(user01); // com.model.design.spring.node01.singleton.UserBean@364841 System.out.println(user02); // com.model.design.spring.node01.singleton.UserBean@c4711c System.out.println(user03); } } 结论Spring单例模式与纯粹的单例设计模式的主要区别尽管使用相同的类加载器来加载两个应用程序上下文,但是UserBean的实例是不一样的。也就是Spring框架中的单例对象是基于应用程序中。 六、单例模式总结 1、注意事项 单例模式注意事项和细节说明 1) 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。 2) 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new Object() 的方式。 3) 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象。 2、优缺点 优点: 1、单例模式只会创建一个对象实例,减少内存消耗 2、设置全局访问点,优化共享资源的访问 缺点: 1、没有接口,很难扩展 2、不利于测试 3、与单一职责原则冲突 七、源代码地址 GitHub地址:知了一笑 https://github.com/cicadasmile/model-arithmetic-parent 码云地址:知了一笑 https://gitee.com/cicadasmile/model-arithmetic-parent

优秀的个人博客,低调大师

Java中多个ifelse语句的替代设计

今天在改老代码的过程中,亲眼见证了一段30个if-else嵌套的代码... 然后搜集了一些资料做了以下简单整理。 概述 ifelse是任何编程语言的重要组成部分。但是我们编写了大量嵌套的if语句,这使得我们的代码更加复杂和难以维护。 接下来,让我们探索如何简化代码的中的ifelse语句写法。 案例研究 我们经常遇到涉及很多条件的业务逻辑,并且每个逻辑都需要不同的处理方式。以Calculator类为例。我们将有一个方法,它接受两个数字和一个运算符作为输入,并根据操作返回结果: public int calculate(int a, int b, String operator) { int result = Integer.MIN_VALUE; if ("add".equals(operator)) { result = a + b; } else if ("multiply".equals(operator)) { result = a * b; } else if ("divide".equals(operator)) { result = a / b; } else if ("subtract".equals(operator)) { result = a - b; } return result; } 我们也可以使用switch语句来实现它: switch (operator) { case "add": result = a + b; break; // other cases } return result; } 在典型的开发中,if语句可能会变得更大,更复杂。此外,当存在复杂条件时,switch语句不适合。 拥有嵌套决策结构的另一个副作用是它们变得难以管理。例如,如果我们需要添加一个新的运算符,我们必须添加一个新的if语句并实现该操作。 重构 可以通过设计模式,来达到我们要的效果。 工厂模式 很多时候,我们遇到ifelse结构,最终在每个分支中执行类似的操作。这提供了提取工厂方法的机会,该工厂方法返回给定类型的对象并基于具体对象行为执行操作。 对于我们的示例,让我们定义一个具有单个apply方法的Operation接口: int apply(int a, int b); } 该方法将两个数字作为输入并返回结果。让我们定义一个用于执行添加的类: public class Addition implements Operation { @Override public int apply(int a, int b) { return a + b; } } 我们现在将实现一个工厂类,它根据给定的运算符返回Operation的实例: public class OperatorFactory { static Map<String, Operation> operationMap = new HashMap<>(); static { operationMap.put("add", new Addition()); operationMap.put("divide", new Division()); // more operators } public static Optional<Operation> getOperation(String operator) { return Optional.ofNullable(operationMap.get(operator)); } } 现在,在Calculator类中,我们可以查询工厂以获取相关操作并应用源数: public int calculateUsingFactory(int a, int b, String operator) { Operation targetOperation = OperatorFactory .getOperation(operator) .orElseThrow(() -> new IllegalArgumentException("Invalid Operator")); return targetOperation.apply(a, b); } 在这个例子中,我们已经看到了如何将责任委托给工厂类提供的松散耦合对象。但是有可能嵌套的if语句只是转移到了工厂类,这违背了我们的目的。 或者,我们可以在Map中维护一个对象存储库,可以查询该存储库以进行快速查找。正如我们所见,OperatorFactory#operationMap服务于我们的目的。我们还可以在运行时初始化Map并将它们配置为查找。 使用枚举 除了使用Map之外,我们还可以使用Enum来标记特定的业务逻辑。之后,我们可以在嵌套的if语句或switch case 语句中使用它们。或者,我们也可以将它们用作对象的工厂并制定策略以执行相关的业务逻辑。 这样可以减少嵌套if语句的数量,并将责任委托给单个Enum值。 让我们看看我们如何实现它。首先,我们需要定义我们的枚举: public enum Operator { ADD, MULTIPLY, SUBTRACT, DIVIDE } 可以观察到,这些值是不同运算符的标签,将进一步用于计算。我们总是可以选择在嵌套的if语句或switch case中使用这些值作为不同的条件,但让我们设计一种将逻辑委托给Enum本身的替代方法。 我们将为每个Enum值定义方法并进行计算。例如: @Override public int apply(int a, int b) { return a + b; } }, // other operators public abstract int apply(int a, int b); 然后在Calculator类中,我们可以定义一个执行操作的方法: public int calculate(int a, int b, Operator operator) { return operator.apply(a, b); } 现在,我们可以通过使用Operator#valueOf()方法将String值转换为Operator来调用该方法: @Test public void test() { Calculator calculator = new Calculator(); int result = calculator.calculate(3, 4, Operator.valueOf("ADD")); assertEquals(7, result); } 命令模式 在前面的讨论中,我们已经看到使用工厂类来返回给定运算符的正确业务对象的实例。稍后,业务对象用于在计算器中执行计算。 我们还可以设计一个Calculator#calculate方法来接受可以在输入上执行的命令。这将是替换嵌套if语句的另一种方法。 我们首先定义我们的Command接口: public interface Command { Integer execute(); } 接下来,让我们实现一个AddCommand: public class AddCommand implements Command { // Instance variables public AddCommand(int a, int b) { this.a = a; this.b = b; } @Override public Integer execute() { return a + b; } } 最后,让我们在Calculator中引入一个接受并执行Command的新方法: public int calculate(Command command) { return command.execute(); } 接下来,我们可以通过实例化AddCommand调用计算并将其发送到Calculator#calculate方法: @Test public void test() { Calculator calculator = new Calculator(); int result = calculator.calculate(new AddCommand(3, 7)); assertEquals(10, result); } 规则引擎 当我们最终编写大量嵌套if语句时,每个条件都描述了一个业务规则,必须对其进行评估才能处理正确的逻辑。规则引擎从主代码中获取了这种复杂性。一个RuleEngine评估规则和返回基于输入的结果。 让我们通过设计一个简单的RuleEngine来演示一个例子,该RuleEngine通过一组规则处理Expression并返回所选规则的结果。首先,我们将定义一个Rule接口: public interface Rule { boolean evaluate(Expression expression); Result getResult(); } 其次,让我们实现一个RuleEngine: public class RuleEngine { private static List<Rule> rules = new ArrayList<>(); static { rules.add(new AddRule()); } public Result process(Expression expression) { Rule rule = rules .stream() .filter(r -> r.evaluate(expression)) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Expression does not matches any Rule")); return rule.getResult(); } } 所述RuleEngine接受一个表达对象,并返回结果。现在,让我们将Expression类设计为一组包含两个Integer对象的Operator,它将被应用: public class Expression { private Integer x; private Integer y; private Operator operator; } 最后让我们定义一个自定义的AddRule类,该类仅在指定ADD操作时进行求值: public class AddRule implements Rule { @Override public boolean evaluate(Expression expression) { boolean evalResult = false; if (expression.getOperator() == Operator.ADD) { this.result = expression.getX() + expression.getY(); evalResult = true; } return evalResult; } } 我们现在将使用Expression调用RuleEngine: @Test public void test() { Expression expression = new Expression(5, 5, Operator.ADD); RuleEngine engine = new RuleEngine(); Result result = engine.process(expression); assertNotNull(result); assertEquals(10, result.getValue()); } 结论通过这些设计模式,可以作为我们的ifelse语句的替代方案,具体用哪一种可以根据你的实际业务场景来决定。 5万人关注的大数据成神之路,不来了解一下吗?5万人关注的大数据成神之路,真的不来了解一下吗?5万人关注的大数据成神之路,确定真的不来了解一下吗? 欢迎您关注《大数据成神之路》

优秀的个人博客,低调大师

JAVA8 MAP新增方法详解

1、compute default V compute(K key,BiFunction<? super K,? super V,? extends V> remappingFunction)Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping). 尝试通过Lambda表达式重新计算给定KEY的映射值并更新MAP(值为null则删除KEY,否则重新写入)。 Map<String, String> tMap = new HashMap<String, String>() { { put("A", "AAA"); put("B", "BBB"); } }; tMap.compute("A", (k, v) -> v == null ? "AAA" : v.concat("AAA"));//KEY存在VALUE不为空且Lambda计算结果不为空,更新KEY System.out.println(tMap); tMap.compute("B", (k, v) -> v == null ? "BBB" : null);//KEY存在VALUE不为空但Lambda计算结果为空,删除KEY System.out.println(tMap); tMap.compute("C", (k, v) -> v == null ? "CCC" : v.concat("CCC"));//KEY不存在但Lambda计算结果不为空,新增KEY System.out.println(tMap); 2、computeIfAbsent default V computeIfAbsent(K key,Function<? super K,? extends V> mappingFunction) If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null. 如果给定的KEY为关联VALUE或关联到null,则尝试通过给定的Lambda函数计算其值并写入MAP(值为null则不写入)。 Map<String,String> map = new HashMap<>(); map.computeIfAbsent("A",k -> null); System.out.println(map); map.computeIfAbsent("B",k -> "BBB"); System.out.println(map); 3、computeIfPresent default V computeIfPresent(K key,BiFunction<? super K,? super V,? extends V> remappingFunction) If the value for the specified key is present and non-null, attempts to compute a new mapping given the key and its current mapped value.如果给定KEY存在映射值且非null,尝试通过Lambda表达式计算新值并更新MAP If the function returns null, the mapping is removed. If the function itself throws an (unchecked) exception, the exception is rethrown, and the current mapping is left unchanged.如果Lambda计算结果为null,则删除KEY。如果Lambda计算发生异常,则原映射关系不变。 Map<String, String> tMap = new HashMap<String, String>() { { put("A", "AAA"); put("B", "BBB"); } }; tMap.computeIfPresent("A", (k, v) -> v == null ? "AAA" : v.concat("AAA"));//Lambda计算结果不为空,更新KEY System.out.println(tMap); tMap.computeIfPresent("B", (k, v) -> v == null ? "BBB" : null);//Lambda计算结果为空,删除KEY System.out.println(tMap);

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册