getresourceasstream方法_【设计模式】第三篇:一篇搞定工厂模式【简单工厂、工厂方法模式、抽象工厂模式】...

c3eff8050350be300136ba51a4355929.png
文章系列目录(持续更新中):

【设计模式】第一篇:概述、耦合、UML、七大原则,详细分析总结(基于Java)

【设计模式】第二篇:单例模式的几种实现And反射对其的破坏

一 为什么要用工厂模式

之前讲解 Spring 的依赖注入的文章时,我们就已经有提到过工厂这种设计模式,我们直接先通过一个例子来看一下究竟工厂模式能用来做什么?

【万字长文】Spring框架 层层递进轻松入门 (IOC和DI)

首先,我们简单的模拟一个对账户进行添加的操作,我们先采用我们以前常常使用的方式进行模拟,然后再给出改进方案

(一) 举一个模拟 Spring IOC 的例子

(1) 以前的程序

首先,按照我们常规的方式先模拟,我们先将一套基本流程走下来

A:Service 层

/**
 * 账户业务层接口
 */
public interface AccountService {
    void addAccount();
}

/**
 * 账户业务层实现类
 */
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao = new AccountDaoImpl();

    public void addAccount() {
        accountDao.addAccount();
    }
}

B:Dao 层

/**
 * 账户持久层接口
 */
public interface AccountDao {
    void addAccount();
}

/**
 * 账户持久层实现类
 */
public class AccountDaoImpl implements AccountDao {

    public void addAccount() {
        System.out.println("添加用户成功!");
    }
}

C:调用

由于,我们创建的Maven工程并不是一个web工程,我们也只是为了简单模拟,所以在这里,创建了一个 Client 类,作为客户端,来测试我们的方法

public class Client {
    public static void main(String[] args) {
        AccountService  as = new AccountServiceImpl();
        as.addAccount();
    }
}

运行的结果,就是在屏幕上输出一个添加用户成功的字样

D:分析:new 的问题

上面的这段代码,应该是比较简单也容易想到的一种实现方式了,但是它的耦合性却是很高的,其中这两句代码,就是造成耦合性高的根由,因为业务层(service)调用持久层(dao),这个时候业务层将很大的依赖于持久层的接口(AccountDao)和实现类(AccountDaoImpl)

private AccountDao accountDao = new AccountDaoImpl();

AccountService as = new AccountServiceImpl();

这种通过 new 对象的方式,使得不同类之间的依赖性大大增强,其中一个类的问题,就会直接导致出现全局的问题,如果我们将被调用的方法进行错误的修改,或者说删掉某一个类,执行的结果就是:

f45f4698c958f59c83115d8b0e80763f.png

编译期就出现了错误,而我们作为一个开发者,我们应该努力让程序在编译期不依赖,而运行时才可以有一些必要的依赖(依赖是不可能完全消除的)

所以,我们应该想办法进行解耦,要解耦就要使调用者被调用者之间没有什么直接的联系,那么工厂模式就可以帮助我们很好的解决这个问题

(2) 工厂模式改进

A:BeanFactory

具体怎么实现呢?在这里可以将 serivice 和 dao 均配置到配置文件中去(xml/properties),通过一个类读取配置文件中的内容,并使用反射技术创建对象,然后存起来,完成这个操作的类就是我们的工厂

注:在这里我们使用了 properties ,主要是为了实现方便,xml还涉及到解析的一些代码,相对麻烦一些,不过我们下面要说的 Spring 就是使用了 xml做配置文件

  • bean.properties:先写好配置文件,将 service 和 dao 以 key=value 的格式配置好

accountService=cn.ideal.service.impl.AccountServiceImpl
accountDao=cn.ideal.dao.impl.AccountDaoImpl
  • BeanFactory

public class BeanFactory {
    //定义一个Properties对象
    private static Properties properties;
    //使用静态代码块为Properties对象赋值
    static {
        try{
            //实例化对象
            properties = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            properties.load(in);
        }catch (Exception e){
            throw  new ExceptionInInitializerError("初始化properties失败");
        }
    }  
}

简单的解释一下这部分代码(当然还没写完):首先就是要将配置文件中的内容读入,这里通过类加载器的方式操作,读入一个流文件,然后从中读取键值对,由于只需要执一次,所以放在静态代码块中,又因为 properties 对象在后面的方法中还要用,所以写在成员的位置

接着在 BeanFactory 中继续编写一个 getBean 方法其中有两句核心代码的意义就是:

  • 通过方法参数中传入的字符串,找到对应的全类名路径,实际上也就是通过刚才获取到的配置内容,通过key 找到 value值

ca0bcff2d5719a4ee619127f88f98eff.png
  • 下一句就是通过 Class 的加载方法加载这个类,实例化后返回

public static Object getBean(String beanName){
    Object bean = null;

    try {
        //根据key获取value
        String beanPath = properties.getProperty(beanName);
        bean = Class.forName(beanPath).newInstance();
    }catch (Exception e){
        e.printStackTrace();
    }
    return bean;
}

B:测试代码:

public class Client {
    public static void main(String[] args) {
        AccountService as =                        (AccountService)BeanFactory.getBean("accountService");
        as.addAccount();
    }
}

C:执行效果:

当我们按照同样的操作,删除掉被调用的 dao 的实现类,可以看到,这时候编译期错误已经消失了,而报出来的只是一个运行时异常,这样就解决了前面所思考的问题

我们应该努力让程序在编译期不依赖,而运行时才可以有一些必要的依赖(依赖是不可能完全消除的)

d71def06942147620e0b3e674c232521.png

(3) 小总结:

为什么使用工厂模式替代了 new 的方式?

打个比方,在你的程序中,如果一段时间后,你发现在你 new 的这个对象中存在着bug或者不合理的地方,或者说你甚至想换一个持久层的框架,这种情况下,没办法,只能修改源码了,然后重新编译,部署,但是如果你使用工厂模式,你只需要重新将想修改的类,单独写好,编译后放到文件中去,只需要修改一下配置文件就可以了

我分享下我个人精简下的理解就是:

【new 对象依赖的是具体事物,而不 new 则是依赖抽象事物】

Break it down:

  • 依赖具体事物,这个很好理解,你依赖的是一个具体的,实实在在内容,它与你系相关,所以有什么问题,都是连环的,可能为了某个点,我们需要修改 N 个地方,绝望

  • 依赖抽象事物,你所调用的并不是一个直接就可以触手可及的东西,是一个抽象的概念,所以不存在上面那种情况下的连环反应

二 三种工厂模式

看完前面的例子,我想大家已经已经对工厂模式有了一个非常直观的认识了

说白了,工厂模式就是使用一种手段,代替了 new 这个操作

以往想要获取一个实例的时候要 new 出来,但是这种方式耦合性就会很高,我们要尽量的减少这种可避免的耦合负担,所以工厂模式就来了

工厂就是在调用者和被调用者之间起一个连接枢纽的作用,调用者和被调用者都只与工厂进行联系,从而减少了两者之间直接的依赖

工厂模式一共有三种 ① 简单工厂模式,② 工厂方法模式 ③ 抽象工厂模式

下面我们一个一个来说

(一) 简单工厂模式

(1) 实现

下面我们以一个车的例子来讲,首先我们有一个抽象的 Car 类

public abstract class Car {
    // 任何汽车都会跑
    public abstract void run();
}

接着就是它的子类,我们先来两个,一个宝马类,一个奔驰类(为阅读方便写成了拼音命名,请勿模仿,不建议)

public class BaoMa extends Car {
    @Override
    public void run() {
        System.out.println("【宝马】在路上跑");
    }
}
public class BenChi extends Car {
    @Override
    public void run() {
        System.out.println("【奔驰】在路上跑");
    }
}

那如果我想要实例化这个类,实际上最原始的写法可以这样(也就是直接 new 出来)

public class Test {
    public static void main(String[] args) {
        Car baoMa = new BaoMa();
        baoMa.run();
        Car benChi = new BenChi();
        benChi.run();
    }
}

如果使用简单工厂模式,就需要创建一个专门的工厂类,用来实例化对象

public class CarFactory {
    public static Car createCar(String type) {
        if ("宝马".equals(type)) {
            return new BaoMa();
        } else if ("奔驰".equals(type)) {
            return new BenChi();
        } else {
            return null;
        }
    }
}

真正去调用的时候,我只需要传入一个正确的参数,通过 CarFactory 创建出想要的东西就可以了,具体怎么去创建就不需要调用者操心了

public class Test {
    public static void main(String[] args) {
        Car baoMa = CarFactory.createCar("宝马");
        baoMa.run();
        Car benChi = CarFactory.createCar("奔驰");
        benChi.run();
    }
}

(2) 优缺点

先说一下优点

简单工厂模式的优点就在于其工厂类中含有必要的逻辑判断(例如 CarFactory 中判断是宝马还是奔驰),客户端只需要通过传入参数(例如传入 “宝马”),动态的实例化想要的类,客户端就免去了直接创建产品的职责,去除了与具体产品的依赖(都不需要知道具体类名了,反正我不负责创建)

但是其缺点也很明显

简单工厂模式的工厂类职责过于繁重,违背了高聚合原则,同时其内容多的情况下,逻辑太复杂。最关键的是,当我想要增加一个新的内容的时候,例如增加一个保时捷,我就不得不去修改 CarFactory 工厂类中的代码,这很显然违背了 “开闭原则”

所以,工厂模式他就来了

(二) 工厂模式

(1) 实现

依旧是一个汽车抽象类,一个宝马类和一个奔驰类是其子类

public abstract class Car {
    // 任何汽车都会跑
    public abstract void run();
}
public class BaoMa extends Car {
    @Override
    public void run() {
        System.out.println("【宝马】在路上跑");
    }
}
public class BenChi extends Car {
    @Override
    public void run() {
        System.out.println("【奔驰】在路上跑");
    }
}

如果是简单工厂类,就会 有一个总的工厂类来实例化对象,为了解决其缺点,工厂类首先需要创建一个汽车工厂接口类

public interface CarFactory {
    // 可以获取任何车
    Car createCar();
}

然后宝马和奔驰类分别实现它,内容就是创建一个对应宝马或者奔驰(实例化宝马类或者奔驰类)

public class BaoMaFactory implements CarFactory {
    @Override
    public Car createCar() {
        return new BaoMa();
    }
}
public class BenChiFactory implements CarFactory {
    @Override
    public Car createCar() {
        return new BenChi();
    }
}

想要获取车的时候,只需要通过多态创建出想要获得的那种车的工厂,然后通过工厂再创建出对应的车,例如我分别拿到奔驰和宝马就可以这样做:

public class Test {
    public static void main(String[] args) {
        // 先去奔驰工厂拿到一台奔驰
        CarFactory benChiFactory = new BenChiFactory();
        // 4S店拿到一台奔驰,给了你
        Car benChi = benChiFactory.createCar();
        benChi.run();

        // 先去宝马工厂拿到一台宝马
        CarFactory baoMaFactory = new BaoMaFactory();
        // 4S店拿到一台宝马,给了你
        Car baoMa = baoMaFactory.createCar();
        baoMa.run();
    }
}

这种情况下,如果我还想要增加一台保时捷类型的车,创建出对应的保时捷类(继承 Car)以及对应保时捷工厂类后后,仍只需要通过以上方法调用即可

// 先去保时捷工厂拿到一台保时捷
CarFactory baoShiJieFactory = new BaoShiJieFactory();
// 4S店拿到一台保时捷,给了你
Car baoShiJie = baoShiJieFactory.createCar();
baoShiJie.run();

(2) 定义

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类

看其结构图

50789d8c0a50486459380c0cecc6b495.png

(3) 优缺点

优点:

  • 对象的创建,被明确到了各个子工厂类中,不再需要在客户端中考虑

  • 新内容增加非常方便,只需要增加一个想生成的类和创建其的工厂类

  • 不违背 “开闭原则”,后期维护,扩展方便

缺点:

  • 代码量显著增加

(三) 抽象工厂模式

抽象工厂模式是一种比较复杂的工厂模式,下面先直接通过代码了解一下

还是说车,我们将车分为两种,一种是普通轿车,一种是卡车,前面的工厂方法模式中,如果不断的增加车的类型,这势必会造成工厂过多,但是对于常见的车来说,还可以寻找可抽取的特点,来进行抽象

所以在此基础之上,我们又分别设定了自动挡和手动挡两种类型,所以两两搭配,就有四种情况了(eg:自动挡卡车,手动挡轿车等等)

(1) 创建抽象产品

  • 首先分别创建普通轿车和卡车的抽象类,然后定义两个方法(这里我就写成一样的了,可以根据轿车和卡车的特点写不同的方法)

public abstract class CommonCar {
    // 所有车都能,停车
    abstract void parking();
    // 所有车都能,换挡
    abstract void shiftGear();
}
public abstract class Truck  {
    // 所有车都能,停车
    abstract void parking();
    // 所有车都能,换挡
    abstract void shiftGear();
}

(2) 实现抽象产品

说明:A是自动的意思,H是手动的意思,eg:CommonCarA 代表普通自动挡轿车

  • 实现抽象产品——小轿车(自动挡)

public class CommonCarA extends CommonCar{
    @Override
    void parking() {
        System.out.println("自动挡轿车A,停车挂P档");
    }

    @Override
    void shiftGear() {
        System.out.println("自动挡轿车A,可换挡 P N D R");
    }
}
  • 实现抽象产品——小轿车(手动挡)

public class CommonCarH extends CommonCar {
    @Override
    void parking() {
        System.out.println("手动挡轿车H,停车挂空挡,拉手刹");
    }

    @Override
    void shiftGear() {
        System.out.println("手动挡轿车H,可换挡 空 1 2 3 4 5 R");
    }
}
  • 实现抽象产品——货车(自动挡)

public class TruckA extends Truck {
    @Override
    void parking() {
        System.out.println("自动挡货车A,停车挂P档");
    }

    @Override
    void shiftGear() {
        System.out.println("自动挡货车A,可换挡 P N D R");
    }
}
  • 实现抽象产品——货车(手动挡)

public class TruckH extends Truck {

    @Override
    void parking() {
        System.out.println("手动档货车H,停车挂空挡,拉手刹");
    }

    @Override
    void shiftGear() {
        System.out.println("手动档货车H,可换挡 空 1 2 3 4 5 R");
    }
}

(3) 创建抽象工厂

public interface CarFactory {
    // 创建普通轿车
    CommonCar createCommonCar();
    // 创建货车
    Truck createTruckCar();
}

(4) 实现抽象工厂

通过自动挡手动挡这两个抽象概念,创建出这两个工厂,创建具有特定实现类的产品对象

  • 自动挡汽车工厂类

public class AutomaticCarFactory implements CarFactory {
    @Override
    public CommonCarA createCommonCar() {
        return new CommonCarA();
    }

    @Override
    public TruckA createTruckCar() {
        return new TruckA();
    }
}
  • 手动挡汽车工厂类

public class HandShiftCarFactory implements CarFactory {
    @Override
    public CommonCarH createCommonCar() {
        return new CommonCarH();
    }

    @Override
    public TruckH createTruckCar() {
        return new TruckH();
    }
}

(5) 测试一下

public class Test {
    public static void main(String[] args) {
        // 自动挡车工厂类
        CarFactory automaticCarFactory = new AutomaticCarFactory();
        // 手动挡车工厂类
        CarFactory handShiftCarFactory = new HandShiftCarFactory();

        System.out.println("=======自动挡轿车系列=======");
        CommonCar commonCarA = automaticCarFactory.createCommonCar();
        commonCarA.parking();
        commonCarA.shiftGear();

        System.out.println("=======自动挡货车系列=======");
        Truck truckA = automaticCarFactory.createTruckCar();
        truckA.parking();
        truckA.shiftGear();

        System.out.println("=======手动挡轿车系列=======");
        CommonCar commonCarH = handShiftCarFactory.createCommonCar();
        commonCarH.parking();
        commonCarH.shiftGear();

        System.out.println("=======手动挡货车系列=======");
        Truck truckH = handShiftCarFactory.createTruckCar();
        truckH.parking();
        truckH.shiftGear();
    }
}

运行结果:

=======自动挡轿车系列=======
自动挡轿车A,停车挂P档
自动挡轿车A,可换挡 P N D R
=======自动挡货车系列=======
自动挡货车A,停车挂P档
自动挡货车A,可换挡 P N D R
=======手动挡轿车系列=======
手动挡轿车H,停车挂空挡,拉手刹
手动挡轿车H,可换挡 空 1 2 3 4 5 R
=======手动挡货车系列=======
手动档货车H,停车挂空挡,拉手刹
手动档货车H,可换挡 空 1 2 3 4 5 R

补充两个概念

  • 产品等级结构产品的等级结构就是其继承结构,例如上述代码中,CommonCar(普通轿车) 是一个抽象类,其子类有 CommonCarA (自动挡轿车)和 CommonCarH(手动挡轿车),则 普通轿车抽象类就与具体自动挡或者手动挡的轿车构成一个产品等级结构。

  • 产品族产品族是同一个工厂生产,位于不同产品等级结构中的一组产品,例如上述代码中,CommonCarA(自动挡轿车)和 TruckA(自动挡货车),都是AutomaticCarFactory(自动挡汽车工厂)这个工厂生成的

0bc5f78a492c46b40ecc6d5ea80abc01.png

(6) 结构图

6b44a19221718bd20d36e6a673d7bf91.png

看着结构图,我们再捋一下

首先 AbstractProductA 和 AbstractProductB 是两个抽象产品,分别对应我们上述代码中的 CommonCar 和 Truck,为什么是抽象的,因为它们可以都有两种不同的实现,即自动挡轿车和自动货车,手动挡轿车和手动挡卡车

ProductA1 和 ProductA2 和 ProductB1 和 ProductB2 就是具体的实现,代表 CommonCarA 和 CommonCarH 和 TruckA 和 TruckH

抽象工厂 AbstractFactory 里包含了所有产品创建的抽象方法,ConcreteFactory1 和 ConcreteFactory2 就是具体的工厂,通常是在运行时再创建一个 ConcreteFactory 的实例,这个工厂再创建具有特定实现的产品对象,也就是说为了创建不同的产品对象,客户端应该使用不同的具体工厂

(7) 反射+配置文件实现优化

抽象工厂说白了就是通过内容抽象的方式,减少了工厂的数量,同时在具体工厂我们可以这么用

CarFactory factory = new AutomaticCarFactory();

具体工厂只需要在初始化的时候出现一次,这也使得修改一个具体工厂也是比较容易的

但是缺点也是非常明显,当我想扩展一,比如加一个拖拉机类型,我就需要修改 CarFactory接口,AutomaticCarFactory 类 HandShiftCarFactory 类,(当然,拖拉机貌似没有什么自动挡,我只是为了举例子),还需要增加拖拉机对应的内容

也就是说,增加的基础上,我还需要修改原先的三个类,这是一个非常显著的缺点

除此之外还有一个问题,如果很多地方都声明了

CarFactory factory = new AutomaticCarFactory();

并且进行了调用,如果我更换了这个工厂,就需要大量的进行修改,很显然这一点是有问题的,我们下面来使用反射优化一下

public class Test {
    public static void main(String[] args) throws Exception {

        Properties properties = new Properties();
        // 使用ClassLoader加载properties配置文件生成对应的输入流
        InputStream in = Test.class.getClassLoader().getResourceAsStream("config.properties");
        // 使用properties对象加载输入流
        properties.load(in);
        //获取key对应的value值
        String factory = properties.getProperty("factory");

        CarFactory automaticCarFactory = (CarFactory) Class.forName(factory).newInstance();

        System.out.println("======轿车系列=======");
        CommonCar commonCarA = automaticCarFactory.createCommonCar();
        commonCarA.parking();
        commonCarA.shiftGear();

        System.out.println("=======货车系列=======");
        Truck truckA = automaticCarFactory.createTruckCar();
        truckA.parking();
        truckA.shiftGear();

    }
}

config.properties

factory=cn.ideal.factory.abstractFactory.AutomaticCarFactory
#factory=cn.ideal.factory.abstractFactory.HandShiftCarFactory

运行结果:

=======轿车系列=======
自动挡轿车A,停车挂P档
自动挡轿车A,可换挡 P N D R
=======货车系列=======
自动挡货车A,停车挂P档
自动挡货车A,可换挡 P N D R

通过反射+配置文件我们就可以使得使用配置文件中的键值对(字符串)来实例化对象,而变量是可以更换的,也就是说程序由编译时转为运行时,增大了灵活性,去除了判断的麻烦

回到前面的问题,如果我们现在要增加一个新的内容,内容的增加没什么好说的,这是必须的,这是扩展,但是对于修改我们却要尽量关闭,现在我们可以通过修改配置文件来达到实例化不同具体工厂的方式

但是还需要修改三个类,以添加新内容,这里还可以通过简单工厂来进行优化,也就是去掉这几个工厂,使用一个简单工厂,其中写入createCommonCar(); 等这些方法, 再配合反射+配置文件也能实现刚才的效果,这样如果新增内容的时候只需要修改配置文件后,再修改这一个类就可以,即增加一个 createXXX 方法,就不需要修改多个内容了

七 结尾

邮箱:ideal_bwh@163.com

如果帮到你的话,那就来关注我吧!

如果您更喜欢微信文章的阅读方式,可以关注我的公众号

如果您更加喜欢PC端的阅读方式,可以访问我的个人博客

域名:www.ideal-20.cn

在这里的我们素不相识,却都在为了自己的梦而努力 ❤

一个坚持推送原创开发技术文章的公众号:理想二旬不止

4ba7c2df9bc2e95f0b9192655efaa196.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/563521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gis根据行政区计算栅格数据计算_亚马逊fba运费根据什么计算?怎么计算?

亚马逊FBA一般有如下费用(仅做参考):1、亚马逊头程(本地发货到FBA仓库的费用)2、订单处理费(1USD / Order)3、拣货打包费(1USD / Pcs)4、重量处理费(0.46USD,这个以1磅一下的large standard size非媒介产品为例,这个是以重量等级的不同从而产…

华硕z97不识别m2固态_华硕H110T +i3 8100T 组装黑苹果Mac mini安装教程

最近组装了一台黑苹果主机,从硬件,到系统安装,驱动安装费了很大的精力,写这篇文章记录下来,希望对像我一样需求的网友有用。目前家里是网通200M的宽带,我喜欢挂pt下一些电影,怎么来播放这些电影…

vue封装websocket_有关WebSocket必须了解的知识

一、前言最近之前时间正好在学习java知识,所以自个想找个小项目练练手,由于之前的ssm系统已经跑了也有大半年了,虽然稀烂,但是功能还是勉强做到了,所以这次准备重构ssm系统,改名为postCode系统(至于为什么前…

list选取多个元素 python_【幼儿园级】0基础学python一本通(上)——AI未来系列1...

在未来面前,每个人都是学生江海升月明,天涯共此时,关注江时!引子本篇为AI未来系列第一篇。为什么要研究学习python?python是未来屠龙的屠龙宝刀,再辅助以我们的高中数学基础(足够用的屠龙术),小…

用polt3画曲面_用SolidWorks建模一个:防滑板曲面造型

防滑板曲面造型2020年4月点底部提取码:eo9z此图用SolidWorks2019版建模,用KeyShot 9.0 渲染(上面两张图) 。SW原文件在今日文件夹里。建模过程1.在上视基准面上画草图。2.曲面拉伸,反向:5 。3.新建基准面,距离上视基准…

lntellijidea怎么创建文件_DBC文件到底是个啥

本文首发自公众号“汽车技术馆”在之前的一篇文章中给大家分享了一些CAN的基本知识,比如CAN通讯是个啥,CAN通讯的机制以及CAN通讯的帧结构等等,相信读过这篇文章的朋友应该都有了一个初步的认识,如果还没有看过的朋友可以在读本文…

at moment的用法 the_值得收藏!初中英语10大词类详解+用法+考点, 这一篇全齐了!...

一、词性的分类词类又叫词性,英语单词根据其在句子中的功用,可以分成十个大类。1.名词 noun n. student 学生2.代词 pronoun pron. you 你3.形容词 adjective adj. happy 高兴的4.副词 adverb adv. quickly 迅速地5.动词 verb v. cut 砍、割6.数词 numer…

属性值动态调整_【VBA】Range对象的常用方法属性(三)

本文继续上一节的Range对象的方法和属性的讲解。上一讲讲到了End属性寻找最后一个已经使用的单元格。这一节继续讲解关于动态找单元格区域方面的属性。Offset 偏移相信学过OFFSET工作表函数的人对这个印象比较深刻,它可是函数中高手必备函数之一。在VBA中&#xff0…

mysql入门到跑路_Mysql入门二十小题(DBA老司机带你删库到跑路)2018.11.26

1、 请介绍数据库管理系统的种类及代表产品RDBMS: mysql oracle mssqlNoSQL: redis mongoab memcache2、 请简述数据库管理系统的作用数据存储,管理数据,备份恢复,安全性,权限管理,3、 请简述RDBMS和NoSQL的特性对比RDBMS:强大的查询功能、强一致性、二级索引、支…

mysql安装包没有安装程序_MySQL5.6的zip包安装教程详解

之前我们都是后缀为.msi的文件,换言之就是傻瓜式安装,但是有些版本不容易控制安装路径,或者数据库编码格式,还有些会安装很多无用的服务,但是都没有后缀为.zip文件简单直接,说是在哪里,就在哪里…

mysql count优化_MySQL count()函数及其优化

很简单,就是为了统计记录数由SELECT返回为了理解这个函数,让我们祭出 employee_tbl 表所有记录统计行的总数计算 Zara 的记录数注意:由于 SQL 查询对大小写不敏感,所以在 WHERE 条件中,无论是写成 ZARA 还是 Zara&…

dz论坛连接mysql数据库_dz论坛搬家后连接数据库等教程

dz搬家后,第一步就是上传源文件到网站根目录和导入数据库然后修改对应的数据库连接配置文件 一共有三个这样修改之后网站就可以访问啦1、config/config_global.php$_config[db][1][dbuser] 数据库用户名;$_config[db][1][dbpw] 数据库密码;$_config[db][1][dbname…

php mysql循环语句怎么写_mysql数据库循环语句该怎么写???

数据库结构num date2 2013-07-245 2013-07-258 2013-08-0310 2013-08-224 2013-09-10最后要在页面中输出为一个行行统计格式7月份 7条记录8月份 18条记录9月份 4条记录要求sql语句只有一句话,有的人会想可以select (count(条件))关键是还要换行的。。有点不会了。回…

ntext在mysql_varchar和text说不清的那些事

数据库定义到char类型的字段时,不知道大家是否会犹豫一下,到底选char、nchar、varchar、nvarchar、text、ntext中哪一种呢?结果很可能是两种,一种是节俭人士的选择:最好是用定长的,感觉比变长能省些空间&am…

字符串转16进制_16、atoi-整数字符串转整数-leetcode8-中等

思路:借助正则表达式。class Solution:def myAtoi(self, s: str) -> int:import repattern re.compile(r^[-]?d) # 生成patterns s.lstrip() #去除左侧空格num_str pattern.findall(s) #找到pattern,返回一个listnum int(*num_str) #用*将list解…

vue移动端通过px动态计算图片宽高_vue图片宽高自适应_移动web图片高度自适应的解决方案...

由于图片的加载是在dom加载完成之后进行的,于是,在手机端浏览网页时,经常会看到页面刚打开时很多内容叠在一起,当图片加载完成后,页面会由于图片加载完成出现明显的抖动针对这个问题,有以下几种解决方案媒体…

mysql日期为00_MySQL 8.0.13 设置日期为0000-00-00 00:00:00时出现的问题

刚开始学习 数据库 操作,今天存数据时发现,保存的时候报错 (Error 1292: Incorrect datetime value: 0000-00-00 for column deleted_at at row 1),之后就搜索了下原因,是因为 MySQL存日期时不允许出现这种格式导致的。下面记录下…

MySQL编程技巧_MySQL学习笔记---MySQL开发技巧

SQL语句分类DDL:数据定义语言 --- CREATE、ALTER、DROP、TRUNCATETPL:事务处理语言 --- COMMIT、ROLLBACK、SAVEPOINT、SET TRANSACTIONDCL:数据控制语言 --- GRANT、REVOKEDML:数据操作语言 --- SELECT、UPDATE、INSERT、DELETEj…

kafka topic 目录存放在哪_Kafka系列文章之安装测试-第2篇

前言上篇文章讲解了 Kafka 的基础概念和架构,了解了基本概念之后,必须得实践一波了,所谓“实践才是检验真理的唯一办法”,后续系列关于 Kafka 的文章都以 kafka_2.11-0.9.0.0 为例;另外为了让大家快速入门,…

mysql的操作语句_Mysql最常用的操作语句收集

Mysql中常用语句简单易学springboot微服务是现在流行的框架,目前大多数做java的人都在使用,java的生态一直很好,各种插件各种第三方jar包推动着java的运行。Mysql是Springboot最常用的数据库,主要原因是Mysql免费而且轻量。考虑性…