2.Java设计模式-----抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory),是23种设计模式之一。抽象工厂模式是这样子定义的:

抽象工厂模式,提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。

       在学习抽象工厂模式之前,最好熟悉简单工厂模式以及工厂方法模式,这样对理解抽象工厂模式会有一定帮助,而且抽象工厂模式是基于工厂方法模式而来的。如果你还没有了解到什么是简单工厂模式以及工厂方法模式,你可以去了解一下:1.大白话讲解-----工厂方法模式(Factory Pattern)     工厂模式------关心的是结果

       你可能看着上面的定义,一时无法理解它到底是什么意思。 你可以接着继续往下面看,看了这个实例,我相信你应该就能够理解上面这句话的含义了。

现在我们有一个新的需求:

        ①现在我有一套系统,系统里面分别用到了MySQL和Oracle数据库。

        ②我需要对这两套数据库进行相同的操作,比如:我要对MySQL和Oracle进行用户信息的相同操作(insert,get用户信息等)

现在既然已经有了相关的需求,那我们现在就可以来对该需求进行一些简单的分析:

        ①数据库两套:MySQL、Oracle

        ②分别要对两套数据库中的数据,都进行insert操作、get信息操作

接下来,我们就来按照我们平常的思路,来编写一下代码了。

①我们现在分别有两个类MySQLUser类、OracleUser类,然后类里都有insertUser()和getUser()方法来实现相关操作

//1.MySQLUser.java
public class MySQLUser {
    public void insertUser(){
        System.out.println("我是MySQL中的insert方法");
    }
    public void getUser(){
        System.out.println("我是MySQL中的getUser方法");
    }
}
//2.OracleUser.java
public class OracleUser {
    public void insertUser(){
        System.out.println("我是Oracle中的insertUser方法");
    }
    public void getUser(){
        System.out.println("我是Oracle中的getUser方法");
    }
}

然后我们在main方法中测试一下:

public class Test {
    public static void main(String[] args) {
        MySQLUser mysql = new MySQLUser();
        mysql.getUser();//打印结果:我是MySQL中的getUser方法
        mysql.insertUser();//打印结果:我是MySQL中的insert方法
        OracleUser oracle = new OracleUser();
        oracle.getUser();//打印结果:我是Oracle中的getUser方法
        oracle.insertUser();//打印结果:我是Oracle中的insertUser方法
    }
}

如上结果,完全可以实现我们的功能。但是,看上去确实有点太low了。如果我有10个乃至100个地方需要用到mysql对象,那么我每次都需要new MySQLUser()才能够获取到一个mysql对象,然后对其进行操作。借用工厂方法模式,我们可以来一个工厂方法Factory来帮助我们去创建mysql对象和oracle对象。

②接下来,我们可以将其进一步进行修改。

       1.从MySQLUser类和OracleUser类中抽取出一个IUser接口,接口包括insertUser()和getUser()抽象方法

       2.MySQLUser类和OracleUser类,分别实现IUser接口,然后重写insertUser()和getUser()方法

       3.创建MySQLFactory和OracleFactory工厂类,主要用来创建用户,从工厂类中可以抽取出一个IFactory接口,接口包括createUser()抽象方法

       4.MySQLFactory类和OracleFactory类,分别实现IFactory接口,并且重写createUser()方法

       5.进行测试

代码实现具体如下:

//1.IUser接口
public interface IUser {
    public void insertUser();
    public void getUser();
}
//2.1 MySQLUser类实现IUser
public class MySQLUser implements IUser {
    @Override
    public void insertUser(){
        System.out.println("我是MySQL中的insert方法");
    }
    @Override
    public void getUser(){
        System.out.println("我是MySQL中的getUser方法");
    }
}
//2.2 OracleUser类实现IUser
public class OracleUser implements IUser {
    @Override
    public void insertUser(){
        System.out.println("我是Oracle中的insertUser方法");
    }
    @Override
    public void getUser(){
        System.out.println("我是Oracle中的getUser方法");
    }
}
//3.IFactory接口
public interface IFactory {
    public IUser createUser();
}
//4.1 MySQLFactory类实现IFactory 
public class MySQLFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new MySQLUser();
    }
}
//4.2 OracleFactory类实现IFactory 
public class OracleFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new OracleUser();
    }
}
//5.测试
public class Test01 {
    public static void main(String[] args) {
        IFactory factory = new MySQLFactory();
        IUser user = factory.createUser();
        user.insertUser(); //打印结果:我是MySQL中的insert方法
        user.getUser();//打印结果:我是MySQL中的getUser方法
    }
}

       如果现在我不用MySQL了,目前要换成Oracle,则只需要将new MySQLFactory()换成new OracleFactory()即可。你会发现这完全就是工厂方法模式。对的。就是工厂方法模式的实现。我们开头就说到:抽象工厂模式是基于工厂方法模式而来的。接下来,我们再继续向着抽象工厂模式继续演进吧

③现在我们又有了新的需求:

          现在MySQL和Oracle中,都有一张日志Log表,我们在insertUser之后,都要向日志表中添加一条数据

    现在我们来对这个需求进行一下简单的分析:

          1.之前MySQLUser和OracleUser分别有一个insertUser()和getUser()方法,目前它们都需要往日志表中添加日志

          2.所以我们现在抽取出一个ILog接口,接口中有一个insertLog()抽象方法

          3.新建一个MySQLLog类和OracleLog类,分别实现ILog接口,然后重写insertLogr()方法

          4.之前IFactory接口已有createUser()功能的情况下,在该接口中新增一个createLog()抽象方法,来满足插入日志的功能

          5.MySQLFactory类和OracleFactory类,因为实现了IFactory接口,需要重写createLog()方法

          6.开启测试

//2.ILog接口
public interface ILog {
    public void insertLog();
}
//3.1 MySQLLog实现ILog接口
public class MySQLLog implements ILog {
    @Override
    public void insertLog() {
        System.out.println("我是MySQL中的insertLog方法");
    }
}
//3.2 OracleLog实现ILog接口
public class OracleLog implements ILog {
    @Override
    public void insertLog() {
        System.out.println("我是Oracle中的insertLog方法");
    }
}
//4.IFactory接口新增createLog()方法
public interface IFactory {
    public IUser createUser();
    public ILog createLog();
}
//5.1 MySQLFactory工厂类重写新增的createLog()方法
public class MySQLFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new MySQLUser();
    }
    @Override
    public ILog createLog() {
        return new MySQLLog();
    }
}
//5.2 OracleFactory工厂类重写新增的createLog()方法
public class OracleFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new OracleUser();
    }
    @Override
    public ILog createLog() {
        return new OracleLog();
    }
}
//6.开启测试
public class Test02 {
    public static void main(String[] args) {
        IFactory factory = new MySQLFactory();
        IUser mysql = factory.createUser();
        mysql.getUser(); //打印结果:我是MySQL中的getUser方法

        ILog log = factory.createLog();
        log.insertLog(); //打印结果:我是MySQL中的insertLog方法
    }
}

④我们现在有个改变,就是说在③中第6步测试中,我们现在业务要废弃MySQL而使用Oracle了,现在我们只需要将第6步中的new MySQLFactory() 换成 new OracleFactory()即可。而无需改动其他代码,就能够解决业务的变动,这就已经明显解决了与具体数据库之间的耦合关系

⑤如果我们现在又要换成SqlServer呢。则我们现在只需要实现如下几步,即可满足要求

         1.创建一个SqlServerUser,来实现已写好的IUser接口,并重写其中的insertUser()和getUser()方法。

         2.创建一个SqlServerFactory,实现已写好的IFactory接口,并重写其中的createUser()方法。

         3.在③中第6步测试中,直接将new MySQLFactory()换成new SqlServerFactory()即可。

         4.这样就可以最大程度上解决功能与业务代码之间的耦合,将修改工作量降到最低。

⑥实际上我们这次代码的重构中,已经使用到了抽象工厂模式,抽象工厂可能表面上看起来貌似与工厂方法模式没什么区别的。所以,抽象工厂模式是基于工厂方法模式而来的。现在你在重头来看一下抽象工厂模式的定义:抽象工厂模式,提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。你也许可能就会有所体会

⑦在该实例中,你完全可以理解成是多个工厂方法的组合。

⑧抽象工厂模式的优点:

        1.方便交换产品系列,诸如在本实例中,如果现在业务需求需要将MySQL替换为Oracle或者SqlServer,你只需要将new MySQLFactory()替换为new OracleFactory()或者new SqlServerFactory()即可满足要求。这样可以在保证在最小改动的情况下而完成对整体业务的修改,起到了最大程度的解耦操作。

        2.在实现过程(xxxFactory类中)和具体使用中(测试类中),我们通过向上造型用到IFactory,IUser,ILog类,我们在具体使用中就用到了上面三个类,我们通过factory.createUser()来创建用户,通过factory.createLog()来插入日志。如果没有new xxxFactory()的话,我们完全不知道我们是在操作哪个类型的数据库,从而达到了实现类和使用之间的隔离。

⑨抽象工厂模式的缺点:

         在我们每次需要createUser和createLog的时候,我们都需要通过IFactory factory = new xxxFactory();来获取到factory对象,然后对其进行相关的操作。如果我现在有100个地方需要使用,则需要来100次new操作,这显然是太扯淡了。这算的上一个缺点吧。

⑩面对⑨中的缺点,我们该如何解决这种问题?

       我们可以使用反射机制来解决,可以参考1.大白话讲解-----工厂方法模式(Factory Pattern)中的⑩部分来做出修改,这就是抽象工厂方法了。

附:全文实例结构图:

Demo实例地址: https://download.csdn.net/download/lzb348110175/11147854

---->如有疑问,请发表评论,或者联系博主:lzb348110175@163.com,欢迎哦^_^

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扛麻袋的少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值