乐趣区

关于java:深入源码理解工厂模式

点赞的靓仔,你是人群中最闪耀的光辉

开题

小学 6 年级的时候老师讲,好好学习、当初临时辛苦,等上初中就好了,至多我的初中生存并不轻松。初三,当初辛苦,等高中就好了,高中生涯更是苦逼中的战斗机。而高三老师说,上大学就好了,上了大学发现,是真的好,没有学业、作业的压力。能够自在翱翔,却不料那是整个人生最初的狂欢,踏入社会从此就是一台不高速运转就会停摆的机器。当前会将更多的业余时间拿来学习。

2 年前在做 Java 讲师的时候,常常会将设计模式分享给学生,学习经典的框架设计。很多框架的设计都用到了设计模式,这里将本人对设计模式的了解与各位分享。

从高内聚、低耦合说起

从入行到当初,便听众人常挂在嘴边的话语,从高级程序员到资深程序员必学的最高内功心法:高内聚、低耦合。要写出高内聚、低耦合的代码,须要肯定的功力。而有这样一群人,将代码编写的经验总结为一套文治秘籍,这就是设计模式。

设计模式 6 大准则

设计模式也恪守肯定的标准,并不是随随便便就做出一套设计模式。而这标准就是设计模式六大准则。

  1. 开闭准则(Open Close Principle)

开闭准则的意思是:对扩大凋谢,对批改敞开。

  1. 里氏代换准则(Liskov Substitution Principle)

任何基类能够呈现的中央,子类肯定能够呈现。

  1. 依赖倒转准则(Dependence Inversion Principle)

这个准则是开闭准则的根底,具体内容:针对接口编程,依赖于形象而不依赖于具体。

  1. 接口隔离准则(Interface Segregation Principle)

这个准则的意思是:应用多个隔离的接口,比应用单个接口要好。它还有另外一个意思是:升高类之间的耦合度。由此可见,其实设计模式就是从大型软件架构登程、便于降级和保护的软件设计思维,它强调升高依赖,升高耦合。

  1. 迪米特法令,又称起码晓得准则(Demeter Principle)

起码晓得准则是指:一个实体该当尽量少地与其余实体之间产生相互作用,使得零碎功能模块绝对独立

  1. 合成复用准则(Composite Reuse Principle)

合成复用准则是指:尽量应用合成 / 聚合的形式,而不是应用继承。

以上内容根本是复制的理论知识,并不是太深奥的货色,了解即可。

工厂模式

在事实中,工厂是用来生产各种产品的,而在面向对象的编程世界,所有皆对象,工厂模式就是用来创立咱们须要的产品,即对象。
而工厂模式又分为:简略工厂、静态方法工厂、形象工厂三种。咱们先来看一波三种工厂的 UML 图,比拟三种模式的区别。

由图中能够看到,三种模式在产品类的构造不变的状况下,针对工厂类有不同的实现,具体如下。

简略工厂

简略工厂的工厂类比较简单,提供一个接管字符串并返回产品的办法,在办法外部依据传入的字符串而返回对应的对象。
工厂类代码 SimpleFactory 如下。

public class SimpleFactory implements Factoty{

    @Override
    public Sender getSender(String senderCode) {switch (senderCode){
            case "email":
                return new EmailSender();
            case "phone":
                return new PhoneSender();}
        return null;
    }
}

可能大家能看出区别,这里的 SimpleFactory 与 UML 图中并不统一,二十实现了一个 Factory 工厂。其实这里是否实现是依据本人的代码设计而来,并不是必须是一般类或者是接口。再来看下一测试代码。

public class SimpleTest {public static void main(String[] args) {SimpleFactory factory = new SimpleFactory();
        Sender email = factory.getSender("email");
        email.send("隔壁老王叫你早点回家吃饭");
    }

}


整个代码的实现比较简单,不晓得大家看测试代码的时候有没有相熟的感觉的?
没错,这就是 Spring 的 Factory 的实现,上面咱们来感受一下 Spring 容器的调用。

public class SpringTest {public static void main(String[] args) {
        // 获取 Spring 容器对象
        ApplicationContext app = new ClassPathXmlApplicationContext("");
        // 从容器获取对象
        SpringTest bean = app.getBean("",SpringTest.class);
        // 调用办法
        bean.run();}
    public void run(){System.out.println("run");
    }
}

比照发下,真的是像两个亲兄弟。其实,Spring 的 BeanFactory 就是应用简略工厂模式来实现的。上源码。

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
    
    // more code
}

ApplicationContext 的 getBean 办法是继承于 BeanFactory 顶级父类,构造如下。

静态方法工厂

静态方法工厂的工厂类不再提供一个创立产品的办法,而是为每个产品提供一个静态方法。代码如下。

/**
 * 静态方法工厂模式
 */
public class StaticFactory {
    //Email 生产办法
    public Sender getEmailSender(){return new EmailSender();
    }
    //Phone 生产办法
    public Sender getPhoneSender(){return new PhoneSender();
    }
}

对于静态方法工厂模式的利用场景,我查阅了材料并没有找到对其利用场景的具体阐明。
这一点我集体了解的是:动态工厂的每一个不同的生产对象都须要提供一个静态方法,而如果生产的对象十分多,那么这个工厂内中将会有十分多的静态方法,比方 1000 个类,须要 1000 个办法来创立,而 10000 个呢?所以我判断静态方法工厂模式不太适宜创立多种对象,而适宜用来创立大量的对象,而这个创建对象的代码可能在很多中央都会应用到,所以应用静态方法来创立,这样就不须要每次都来创立工厂对象了。
我的推断来源于 JDK 源码。

Calendar 的静态方法工厂

Calender 对外提供了 4 个创建对象的 getInstance 办法,别离对应不同的实现,源码如下。

Executers 的静态方法工厂

线程池是工作中比拟罕用的,而 Executers 工具类也提供了 4 种线程池的默认实现。也是应用了静态方法工厂模式来实现的。

public class ExecutersDemo {public static void main(String[] args) {ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorService executorService1 = Executors.newFixedThreadPool(5);
        ExecutorService executorService2 = Executors.newCachedThreadPool();
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
    }
}

其实,相似的还要很多,比方包装类的 valueOf 办法、NumberFormat 的 newInstance 办法等等,通过源码钻研,咱们能够轻易的找到动态工厂办法的套路:

  1. 可能应用的中央较多,而通过静态方法以防止创立过多的工厂对象
  2. 不实用过多的生产对象形式,通常一类的动态工厂办法数量不会超过 10 个
  3. 其实就是简略的静态方法创建对象

形象工厂模式

形象工厂模式我认为是对动态工厂模式的进一步晋升,同样,其工厂的复杂程度也相应的晋升。先上测试代码。

AbstractFactory

public abstract class AbstractFactory {
    // 形象层提供创建对象的办法
    public abstract Sender getSender();}

EmailFactory

public class EmailFactory extends AbstractFactory{
    @Override
    public Sender getSender() {return new EmailSender();
    }
}

PhoneFactory

public class PhoneFactory extends AbstractFactory{
    @Override
    public Sender getSender() {return new PhoneSender();
    }
}

形象工厂在动态工厂的根底上做了降级,动态工厂是一个对象对应一个办法,而形象工厂则间接应用一个工厂对应一个对象。

这样的形象工厂模式的了解是我在最后学习工厂模式时候的了解。但过后并没有深入研究形象工厂的利用场景,以至于对形象工厂的了解有一些偏差,这一次一起将这个坑给补上。

首先,形象工厂模式的利用场景并不是创立繁多的产品对象。而是用来创立一个系列的产品,这个概念称之为‘产品族’,看图。

这是从业务场景剥离进去的构造,也不难理解。比方一个贷款性能,图种能够看到有两种角色,一种是产品工厂,一种是产品,这一点和咱们后面讲到的工厂模式是相似的,然而区别在于,每个工厂不再是只生产一种产品,而是一系列的产品。如果感觉比拟难了解咱们能够再看一个例子:

苹果公司生产什么产品呢?平板、手机、表、电脑。华为也会生产这些产品:平板、手机、表、电脑。这样的比拟就比拟清晰,苹果和华为工厂都有本人的产品族,且产品族是相似的。这种状况就能够应用形象工厂模式。

UML 类图如下。

网上看了很多相干的文章,总结形象工厂模式有一下特点:
1、产品被划分为多个产品族,即下面的例子
2、零碎一次仅生产应用其中一个族的产品。即每次都会应用同一个族的产品,比方你是苹果粉,那么只能应用苹果的产品,华为粉则只能应用华为的产品。
形象工厂的优缺点:
1、形象工厂模式的纵向扩大 (扩大工厂) 非常容易
2、形象工厂模式横向扩大(扩大产品) 十分艰难,因为在产品族新增一个产品会导致整个工厂及产品代码的批改。

退出移动版