GoF之工厂模式

GoF是指二十三种设计模式

GoF23种设计模式可分为三大类:

  • 创建型(5个):解决对象创建问题。

      • 单例模式

      • 工厂方法模式

      • 抽象工厂模式

      • 建造者模式

      • 原型模式

  • 结构型(7个):一些类或对象组合在一起的经典结构。

      • 代理模式

      • 装饰模式

      • 适配器模式

      • 组合模式

      • 享元模式

      • 外观模式

      • 桥接模式

  • 行为型(11个):解决类或对象之间的交互问题。

      • 策略模式

      • 模板方法模式

      • 责任链模式

      • 观察者模式

      • 迭代子模式

      • 命令模式

      • 备忘录模式

      • 状态模式

      • 访问者模式

      • 中介者模式

      • 解释器模式

工厂模式是解决对象创建问题的,所以工厂模式属于创建型设计模式。这里为什么学习工厂模式呢?这是因为Spring框架底层使用了大量的工厂模式。

1.1工厂模式的三种形态

工厂模式通常有三种形态:

  • 第一种:简单工厂模式(Simple Factory):不属于23种设计模式之一。简单工厂模式又叫做静态工厂模式。简单工厂模式是工厂模式的一种特殊实现。

  • 工厂方法模式(Factory Method):是二十三种设计模式之一。

  • 抽象工厂模式(Abstract Factory):是二十三种设计模式之一。

1.2 简单工厂模式

简单工厂模式的角色包括三个:

  • 抽象产品:角色

  • 具体产品:角色

  • 工厂类:角色

代码如下:

抽象产品角色:

package com.powernode.factory;

/**
* 武器(抽象产品角色)
* @author 耀耀
* @version 1.0
* @className Weapon
* @since 1.0
**/
public abstract class Weapon {
   /**
    * 所有的武器都有攻击行为
    */
   public abstract void attack();
}

具体产品角色:

package com.powernode.factory;

/**
* 坦克(具体产品角色)
* @author 耀耀
* @version 1.0
* @className Tank
* @since 1.0
**/
public class Tank extends Weapon{
   @Override
   public void attack() {
       System.out.println("坦克开炮!");
  }
}
package com.powernode.factory;

/**
* 战斗机(具体产品角色)
* @author 耀耀
* @version 1.0
* @className Fighter
* @since 1.0
**/
public class Fighter extends Weapon{
   @Override
   public void attack() {
       System.out.println("战斗机投下原子弹!");
  }
}
package com.powernode.factory;

/**
* 匕首(具体产品角色)
* @author 耀耀
* @version 1.0
* @className Dagger
* @since 1.0
**/
public class Dagger extends Weapon{
   @Override
   public void attack() {
       System.out.println("砍他丫的!");
  }
}

工厂类角色:

package com.powernode.factory;

/**
* 工厂类角色
* @author 耀耀
* @version 1.0
* @className WeaponFactory
* @since 1.0
**/
public class WeaponFactory {
   /**
    * 根据不同的武器类型生产武器
    * @param weaponType 武器类型
    * @return 武器对象
    */
   public static Weapon get(String weaponType){
       if (weaponType == null || weaponType.trim().length() == 0) {
           return null;
      }
       Weapon weapon = null;
       if ("TANK".equals(weaponType)) {
           weapon = new Tank();
      } else if ("FIGHTER".equals(weaponType)) {
           weapon = new Fighter();
      } else if ("DAGGER".equals(weaponType)) {
           weapon = new Dagger();
      } else {
           throw new RuntimeException("不支持该武器!");
      }
       return weapon;
  }
}

测试程序(客户端程序):

package com.powernode.factory;

/**
* @author 耀耀1
* @version 1.0
* @className Client
* @since 1.0
**/
public class Client {
   public static void main(String[] args) {
       Weapon weapon1 = WeaponFactory.get("TANK");
       weapon1.attack();

       Weapon weapon2 = WeaponFactory.get("FIGHTER");
       weapon2.attack();

       Weapon weapon3 = WeaponFactory.get("DAGGER");
       weapon3.attack();
  }
}

简单工厂模式的优点:

  • 客户端程序不需要关心对象的创建细节,需要哪个对象时,只需要向工厂索要即可,初步实现了责任的分离。客户端只负责“消费”,工厂负责“生产”。生产和消费分离。

简单工厂模式的缺点:

  • 缺点1:工厂类集中了所有产品的创造逻辑,形成一个无所不知的全能类,有人把它叫做上帝类。显然工厂类非常关键,不能出问题,一旦出问题,整个系统瘫痪。

  • 缺点2:不符合OCP开闭原则,在进行系统扩展时,需要修改工厂类。

Spring中的BeanFactory就使用了简单工厂模式。

1.3 工厂方法模式

工厂方法模式既保留了简单工厂模式的优点,同时又解决了简单工厂模式的缺点。

工厂模式的角色包括:

  • 抽象工厂角色

  • 具体工厂角色

  • 抽象产品角色

  • 具体产品角色

代码如下:

package com.powernode.factory;

/**
* 武器类(抽象产品角色)
* @author 耀耀
* @version 1.0
* @className Weapon
* @since 1.0
**/
public abstract class Weapon {
   /**
    * 所有武器都有攻击行为
    */
   public abstract void attack();
}

具体产品角色:

package com.powernode.factory;

/**
* 具体产品角色
* @author 耀耀
* @version 1.0
* @className Gun
* @since 1.0
**/
public class Gun extends Weapon{
   @Override
   public void attack() {
       System.out.println("开枪射击!");
  }
}

抽象工厂角色:

package com.powernode.factory;

/**
* 武器工厂接口(抽象工厂角色)
* @author 耀耀
* @version 1.0
* @className WeaponFactory
* @since 1.0
**/
public interface WeaponFactory {
   Weapon get();
}

具体工厂角色:

package com.powernode.factory;

/**
* 具体工厂角色
* @author 耀耀
* @version 1.0
* @className GunFactory
* @since 1.0
**/
public class GunFactory implements WeaponFactory{
   @Override
   public Weapon get() {
       return new Gun();
  }
}

具体工厂角色:

package com.powernode.factory;

/**
* 具体工厂角色
* @author 耀耀
* @version 1.0
* @className FighterFactory
* @since 1.0
**/
public class FighterFactory implements WeaponFactory{
   @Override
   public Weapon get() {
       return new Fighter();
  }
}

客户端程序:

package com.powernode.factory;

/**
* @author 耀耀
* @version 1.0
* @className Client
* @since 1.0
**/
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();
  }
}

如果想扩展一个新的产品,只要新增一个产品类,再新增一个该产品对应的工厂即可,例如新增:匕首

增加:具体产品角色

package com.powernode.factory;

/**
* @author 耀耀
* @version 1.0
* @className Dagger
* @since 1.0
**/
public class Dagger extends Weapon{
   @Override
   public void attack() {
       System.out.println("砍丫的!");
  }
}

增加:具体工厂角色

package com.powernode.factory;

/**
* @author 耀耀
* @version 1.0
* @className DaggerFactory
* @since 1.0
**/
public class DaggerFactory implements WeaponFactory{
   @Override
   public Weapon get() {
       return new Dagger();
  }
}

我们可以看到在进行功能扩展的时候,不需要修改之前的源代码,显然工厂方法模式符合OCP原则。

工厂方法模式的优点:

  • 一个调用者想创建一个对象,只要知道其名称就可以了。

  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

  • 屏蔽产品的具体实现,调用者只关心产品的接口。

工厂方法模式的缺点:

  • 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

2,Bean的实例化方式

Spring为Bean提供了多种实例化方式,通常包括4种方式。(也就是说在Spring中为Bean对象的创建准备了多种方案,目的是:更加灵活)

第一种:通过构造方法实例化

默认情况下,会调用Bean的无参数构造方法

第二种:通过简单工厂模式实例化

第一步:定义一个Bean

package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className Vip
* @since 1.0
**/
public class Vip {
}

第二步:编写简单工厂模式当中的工厂类

package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className VipFactory
* @since 1.0
**/
public class VipFactory {
   public static Vip get(){
       return new Vip();
  }
}

第三步:在Spring配置文件中指定创建该Bean方法(使用factory-method属性指定)

<bean id="vipBean" class="com.powernode.spring6.bean.VipFactory" factory-method="get"/>

第四步:编写测试程序

@Test
public void testSimpleFactory(){
   ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
   Vip vip = applicationContext.getBean("vipBean", Vip.class);
   System.out.println(vip);
}

第三种:通过factory-bean实例化

这种方式本质上是:通过工厂方法模式经行实例化。

第一步:定义一个Bean

package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className Order
* @since 1.0
**/
public class Order {
}

第二步:定义具体工厂类,工厂类中定义实力方法

package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className OrderFactory
* @since 1.0
**/
public class OrderFactory {
   public Order get(){
       return new Order();
  }
}

第三步:在Spring配置文件中指定factory-bean以及factory-method

<bean id="orderFactory" class="com.powernode.spring6.bean.OrderFactory"/>
<bean id="orderBean" factory-bean="orderFactory" factory-method="get"/>

第四步:编写测试程序

@Test
public void testSelfFactoryBean(){
   ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
   Order orderBean = applicationContext.getBean("orderBean", Order.class);
   System.out.println(orderBean);
}

第四种:通过FactoryBean接口实例化

以上的第三种方式中,factory-bean是我们自定义的,factory-method也是我们自己定义的。

在Spring中,当你编写的类直接实现FactoryBean接口之后,factory-bean不需要指定了,factory-method也不需要指定了。

factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。

第一步:定义一个Bean

package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className Person
* @since 1.0
**/
public class Person {
}

第二步:编写一个类实现FactoryBean接口

package com.powernode.spring6.bean;

import org.springframework.beans.factory.FactoryBean;

/**
* @author 耀耀
* @version 1.0
* @className PersonFactoryBean
* @since 1.0
**/
public class PersonFactoryBean implements FactoryBean<Person> {

   @Override
   public Person getObject() throws Exception {
       return new Person();
  }

   @Override
   public Class<?> getObjectType() {
       return null;
  }

   @Override
   public boolean isSingleton() {
       // true表示单例
       // false表示原型
       return true;
  }
}

第三步:在Spring配置文件中配置FactoryBean

<bean id="personBean" class="com.powernode.spring6.bean.PersonFactoryBean"/>

测试程序

@Test
public void testFactoryBean(){
   ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
   Person personBean = applicationContext.getBean("personBean", Person.class);
   System.out.println(personBean);

   Person personBean2 = applicationContext.getBean("personBean", Person.class);
   System.out.println(personBean2);
}

FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的

6.5 BeanFactory 和 FactoryBean的区别

BeanFactory

Spring IoC容器的顶级对象,BeanFactory被翻译为“Bean工厂”,在Spring的IoC容器中,"Bean工厂"负责创建Bean对象。

FactoryBean

FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。

在Spring中,Bean可以分为两类:

  • 第一类:普通Bean

  • 第二类:工厂Bean(记住:工厂Bean也是一种Bean,只不过这种Bean比较特殊,它可以辅助Spring实例化其它Bean对象。)

3,Bean的生命周期

3.1 什么是Bean的生命周期

Spring其实就是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。

所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。

什么时候创建Bean对象?

创建Bean对象的前后会调用什么方法?

Bean对象什么时候销毁?

Bean对象的销毁前后调用什么方法?

3.2 为什么要知道Bean的生命周期

其实生命周期的本质是:在哪个时间节点上调用了哪个类的哪个方法。

我们需要充分的了解在这个生命线上,都有哪些特殊的时间节点。

只有我们知道了特殊的时间节点都在哪,到时我们才可以确定代码写到哪。

我们可能需要在某个特殊的时间点上执行一段特定的代码,这段代码就可以放到这个节点上。当生命线走到这里的时候,自然会被调用。

3.3 Bean的生命周期之五步

Bean生命周期的管理,可以参考Spring的:AbstractAutowireCapableBeanFactory类的doCreateBean()方法。

Bean生命周期可以粗略的划分为五大步:

  • 第一步:实例化Bean

  • 第二步:Bean属性赋值

  • 第三步:初始化Bean

  • 第四步:使用Bean

  • 第五步:销毁Bean

代码测试一下

package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className User
* @since 1.0
**/
public class User {
   private String name;

   public User() {
       System.out.println("1.实例化Bean");
  }

   public void setName(String name) {
       this.name = name;
       System.out.println("2.Bean属性赋值");
  }

   public void initBean(){
       System.out.println("3.初始化Bean");
  }

   public void destroyBean(){
       System.out.println("5.销毁Bean");
  }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

   <!--
   init-method属性指定初始化方法。
   destroy-method属性指定销毁方法。
   -->
   <bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
       <property name="name" value="zhangsan"/>
   </bean>

</beans>

测试程序

package com.powernode.spring6.test;

import com.powernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author 耀耀
* @version 1.0
* @className BeanLifecycleTest
* @since 1.0
**/
public class BeanLifecycleTest {
   @Test
   public void testLifecycle(){
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
       User userBean = applicationContext.getBean("userBean", User.class);
       System.out.println("4.使用Bean");
       // 只有正常关闭spring容器才会执行销毁方法
       ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
       context.close();
  }
}

注意事项:

  • 第一:只有正常关闭的spring容器,bean的销毁才会被调用。

  • 第二:ClassPathXmlApplicationContex类才有ckose()方法。

  • 第三:配置文件中的int-method指定初始化方法。destroy-method指定销毁方法。

3.4 Bean生命周期之七步走

在以上的5步中,第3步是初始化Bean,如果你还想在初始化前和初始化后添加代码,可以加入“Bean后处理器”。

编写一个类实现BeanPostProcessor类,并且重写before和after方法:

package com.powernode.spring6.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
* @author 耀耀
* @version 1.0
* @className LogBeanPostProcessor
* @since 1.0
**/
public class LogBeanPostProcessor implements BeanPostProcessor {
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       System.out.println("Bean后处理器的before方法执行,即将开始初始化");
       return bean;
  }

   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
       System.out.println("Bean后处理器的after方法执行,已完成初始化");
       return bean;
  }
}

在spring.xml文件中配置“Bean后处理器”:

<!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>

一定要注意:在spring.xml文件中配置的Bean后处理器将作用于当前配置文件中所有的Bean。

4,Bean的循环依赖问题

4.1什么是Bena的循环依赖

A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你,你也依赖我。

比如:丈夫类Husband,妻子类Wife。Husband中有Wife的引用。Wife中有Husband的引用。

package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className Husband
* @since 1.0
**/
public class Husband {
   private String name;
   private Wife wife;
}
package com.powernode.spring6.bean;

/**
* @author 耀耀
* @version 1.0
* @className Wife
* @since 1.0
**/
public class Wife {
   private String name;
   private Husband husband;
}

在singleton + set注入的情况下,循环依赖是没有问题的。Spring可以解决这个问题。

当循环依赖的所有Bean的scope="prototype"的时候,产生的循环依赖,Spring是无法解决的,会出现BeanCurrentlyInCreationException异常。

大家可以测试一下,以上两个Bean,如果其中一个是singleton,另一个是prototype,是没有问题的。

构造方法注入会导致**实例化对象的过程和对象属性赋值的过程没有分离开,必须在一起完成导致的。**

Spring为什么可以解决set + singleton模式下循环依赖?

根本的原因在于:这种方式可以做到将“实例化Bean”和“给Bean属性赋值”这两个动作分开去完成。

实例化Bean的时候:调用无参数构造方法来完成。此时可以先不给属性赋值,可以提前将该Bean对象“曝光”给外界。

给Bean属性赋值的时候:调用setter方法来完成。

两个步骤是完全可以分离开去完成的,并且这两步不要求在同一个时间点上完成。

也就是说,Bean都是单例的,我们可以先把所有的单例Bean实例化出来,放到一个集合当中(我们可以称之为缓存),所有的单例Bean全部实例化完成之后,以后我们再慢慢的调用setter方法给属性赋值。这样就解决了循环依赖的问题。

那么在Spring框架底层源码级别上是如何实现的呢?请看:

在以上类中包含三个重要的属性:

  • *Cache of singleton objects: bean name to bean instance.* 单例对象的缓存:key存储bean名称,value存储Bean对象【一级缓存】

  • *Cache of early singleton objects: bean name to bean instance.* 早期单例对象的缓存:key存储bean名称,value存储早期的Bean对象【二级缓存】

  • *Cache of singleton factories: bean name to ObjectFactory.* 单例工厂缓存:key存储bean名称,value存储该Bean对应的ObjectFactory对象【三级缓存】

这三个缓存其实本质上是三个Map集合。

我们再来看,在该类中有这样一个方法addSingletonFactory(),这个方法的作用是:将创建Bean对象的ObjectFactory对象提前曝光。

从源码中可以看到,spring会先从一级缓存中获取Bean,如果获取不到,则从二级缓存中获取Bean,如果二级缓存还是获取不到,则从三级缓存中获取之前曝光的ObjectFactory对象,通过ObjectFactory对象获取Bean实例,这样就解决了循环依赖的问题。

总结:

Spring只能解决setter方法注入的单例bean之间的循环依赖。ClassA依赖ClassB,ClassB又依赖ClassA,形成依赖闭环。Spring在创建ClassA对象后,不需要等给属性赋值,直接将其曝光到bean缓存当中。在解析ClassA的属性时,又发现依赖于ClassB,再次去获取ClassB,当解析ClassB的属性时,又发现需要ClassA的属性,但此时的ClassA已经被提前曝光加入了正在创建的bean的缓存中,则无需创建新的的ClassA的实例,直接从缓存中获取即可。从而解决循环依赖问题。

Spring(Bean详解)的更多相关文章

  1. Spring Bean 详解

    Spring Bean 详解 Ioc实例化Bean的三种方式 1 创建Bean 1 使用无参构造函数 这也是我们常用的一种.在默认情况下,它会通过反射调⽤⽆参构造函数来创建对象.如果类中没有⽆参构造函 ...

  2. Spring(3)——装配 Spring Bean 详解

    装配 Bean 的概述 前面已经介绍了 Spring IoC 的理念和设计,这一篇文章将介绍的是如何将自己开发的 Bean 装配到 Spring IoC 容器中. 大部分场景下,我们都会使用 Appl ...

  3. Spring Bean详解

    Spring Bean 在Spring的应用中,Spring IoC容器可以创建.装配和配置应用组件对象,这里的组件对象称为Bean. Bean的配置 Spring可以看作一个大型工厂,用于生产和管理 ...

  4. Spring二 Bean详解

    Bean详解 Spring框架的本质其实是:通过XML配置来驱动Java代码,这样就可以把原本由java代码管理的耦合关系,提取到XML配置文件中管理.这样就实现了系统中各组件的解耦,有利于后期的升级 ...

  5. (转)java之Spring(IOC)注解装配Bean详解

    java之Spring(IOC)注解装配Bean详解   在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...

  6. spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean ...

  7. spring配置文件详解--真的蛮详细

    spring配置文件详解--真的蛮详细   转自: http://book.51cto.com/art/201004/193743.htm 此处详细的为我们讲解了spring2.5的实现原理,感觉非常 ...

  8. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

  9. J2EE进阶(四)Spring配置文件详解

    J2EE进阶(四)Spring配置文件详解 前言 Spring配置文件是用于指导Spring工厂进行Bean生产.依赖关系注入(装配)及Bean实例分发的"图纸".Java EE程 ...

  10. spring事务详解(二)简单样例

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

随机推荐

  1. 浙大版《C语言程序设计(第3版)》题目集 练习3-3 统计学生平均成绩与及格人数 (15 分)

    练习3-3 统计学生平均成绩与及格人数 (15 分) 本题要求编写程序,计算学生们的平均成绩,并统计及格(成绩不低于60分)的人数.题目保证输入与输出均在整型范围内. 输入格式: 输入在第一行中给出非 ...

  2. 【Android异常】关于静态注册BroadcastReceiver接收不到自定义广播的问题

    Android 8.0以上需要setComponent()来指定包名和类名,第1个参数是指接收广播类的包名,第2个参数是指接收广播类的完整类名.静态广播1.先使用Android Studio创建一个广 ...

  3. CSS设置边距

    1.内边距 所有的 ​HTML ​元素基本都是以矩形为基础. 每个 HTML 元素周围的矩形空间由三个重要的属性来控制: ​padding(内边距)​ ​margin(外边距)​ ​border(边框 ...

  4. python——pkl文件

    pkl文件是python里面保存文件的一种格式,如果直接打开会显示一堆序列化的东西. cPickle在python3中更名为pickle 使用方式如下: import pickle as p shop ...

  5. ARM体系与架构【一】

    由于笔试题(摩尔线程笔试题)也出现了相关的题目,所以也顺便为此做一点点小准备. 1.ARM用什么类型的指令集 ARM架构用的是RISC精简指令集. 2.RISV与RISC指令集有什么区别 3.ARM架 ...

  6. 基于C语言的小学四则运算出题器

    一.实验目的: 1.帮助老师产出每周随机的300道含有两个运算符的四则运算,. 2.每次题目的产出均为随机,增强同学的四则运算能力. 二.实验环境: Visual C++ 三.实验内容: 1.实现随机 ...

  7. idea导入数据库

    yml文件(在启动项文件(main)里,eg:springbook文件里面) sh-bean里org.example.sh.beans的Category类   CategoryDAO名字要和Categ ...

  8. Java基础学习——循环取最接近某个值的方法

    if(diff<mindiff) mindiff=diff;//循环取最小值 float value = (float) fenzi/fenmu;//整数相除结果会自动转换为整数.即使强制转换为 ...

  9. 按正斜线输出M*N的矩阵

    public static void outMatrix(int[][] array) { for(int row=0;row<array.length;row++) { int scolumn ...

  10. python去除前中后多处空格的方法

    x=" asdf ada都 是 年 费 sdf sf " print("".join(x.split())) 测试全角半角空格都没有了