zoukankan      html  css  js  c++  java
  • 【设计模式学习笔记】 之 简单工厂模式

     简介:工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,拒绝客服端程序员通过new创建需要的实例,并且是通过使用一个共同的接口来指向新创建的对象,即接口引用指向实现类对象,是多态的灵活运用。

    举例1【未使用工厂模式】:

    一个家庭中有多辆汽车,这个家庭想去出游,需要先传一个Car到Family中持有,才能出游。

    首先考虑多辆汽车,都有同样的run方法,抽取公共接口如下:

    1 package com.mi.simplefactory.simplefactory1;
    2 
    3 /**
    4  * 汽车接口
    5  */
    6 public interface Car {
    7 
    8     public void run();
    9 }

    现在假设有两辆汽车(多辆同理),HondaCar (本田)和 BenzCar(奔驰),都实现了Car接口

     1 package com.mi.simplefactory.simplefactory1;
     2 
     3 public class HondaCar implements Car{
     4 
     5     @Override
     6     public void run() {
     7         System.out.println("本田上路,请勿抛砖");
     8     }
     9 
    10     
    11 }
     1 package com.mi.simplefactory.simplefactory1;
     2 
     3 public class BenzCar implements Car {
     4 
     5     @Override
     6     public void run() {
     7         System.out.println("奔驰出行,请勿追尾");
     8     }
     9 
    10 }

    这里需要一个Family类,她应持有一个私有Car的引用,使用Family的构造方法进行初始化Car引用,Family中有一个travel方法

     1 package com.mi.simplefactory.simplefactory1;
     2 
     3 public class Family {
     4 
     5     private Car car;
     6 
     7     public Family(Car car) {
     8         this.car = car;
     9     }
    10     public Family() {}
    11     public void travel() {
    12         System.out.println("全家出游!");
    13         car.run();
    14         System.out.println("玩的愉快");
    15     }
    16 }

    编写测试类,发现需要通过new 不同的Car实现类实例就可以改变汽车实际类型

     1 package com.mi.simplefactory.simplefactory1;
     2 
     3 public class Test {
     4 
     5     public static void main(String[] args) {
     6         /**
     7          * 问题来了:family换个车必须要new不同的车,必须要修改代码,重新编译才能
     8          *                     正确更换汽车,还有,可不可以不用new的方式获取汽车?
     9          */
    10 //        Family family = new Family(new HondaCar());
    11         Family family = new Family(new BenzCar());
    12         family.travel();
    13     }
    14 }

    输出:

    先注掉11行,解开10行,运行

    全家出游!
    本田上路,请勿抛砖
    玩的愉快

    注掉10,解开11,运行

    全家出游!
    奔驰出行,请勿追尾
    玩的愉快

    举例2【分支判断实现工厂】:

    这里Car接口和Car接口的实现类不变,重写一个Family类,为car引用设置get set方法,去掉有参构造方法

     1 package com.mi.simplefactory.simplefactory2;
     2 
     3 import com.mi.simplefactory.simplefactory1.Car;
     4 
     5 public class Family {
     6 
     7     private Car car;
     8 
     9     public Family() {}
    10     public void travel() {
    11         System.out.println("全家出游!");
    12         car.run();
    13         System.out.println("玩的愉快");
    14     }
    15     public Car getCar() {
    16         return car;
    17     }
    18     public void setCar(Car car) {
    19         this.car = car;
    20     }
    21     
    22     
    23 }

    创建一个工厂,通过获取汽车的类名为参数,内部if分支判断,实例化内部持有的car引用,还有有一个静态方法getInstance(),获取该 Car的实例

     1 package com.mi.simplefactory.simplefactory2;
     2 
     3 import com.mi.simplefactory.simplefactory1.BenzCar;
     4 import com.mi.simplefactory.simplefactory1.Car;
     5 import com.mi.simplefactory.simplefactory1.HondaCar;
     6 
     7 public class Factory {
     8 
     9     private Car car;
    10     public Factory(String carName) {
    11         if(carName.equals("BenzCar")) {
    12             this.car = new BenzCar();
    13         }
    14         if(carName.equals("HondaCar")) {
    15             this.car = new HondaCar();
    16         }
    17     }
    18     public Car getInstance() {
    19         return car;
    20     }
    21     
    22 }

    测试类

     1 package com.mi.simplefactory.simplefactory2;
     2 
     3 import com.mi.simplefactory.simplefactory1.Car;
     4 
     5 public class Test {
     6 
     7     public static void main(String[] args) {
     8         /**
     9          * 此包中的factory可以不使用new的方式获取汽车
    10          */
    11         Family family = new Family();
    12 //        Factory factory = new Factory("HondaCar");
    13         Factory factory = new Factory("BenzCar");
    14         Car car = factory.getInstance();
    15         family.setCar(car);
    16         family.travel();
    17     }
    18 
    19 }

    输出就不贴出来了,和之前的输出是一样的。

    这个例子,我们的确通过一个工厂去得到我们需要的实例,但是,如果汽车特别的多,我们是不是需要写无数个分支判断啊?代码很冗长,效率不高,于是我们想到了通过反射来实现,于是有了第三个例子

    举例3【通过反射方式】:

    学过反射的同学都应该明白,我们可以通过一个properties配置文件去动态改变代码中产生的代码,这是种可以不改变代码的情况下使用的很方便的方式

    创建一个properties配置文件:config.properties,(这里直接写好了两个,方便切换)

    #Car=com.mi.simplefactory.simplefactory1.BenzCar
    Car=com.mi.simplefactory.simplefactory1.HondaCar

    创建Factory类

     1 package com.mi.simplefactory.simplefactory3;
     2 
     3 import java.io.IOException;
     4 import java.io.InputStream;
     5 import java.util.Properties;
     6 
     7 import com.mi.simplefactory.simplefactory1.Car;
     8 
     9 public class Factory {
    10 
    11     private Factory() {} //拒绝客服端程序员new工厂对象,仅提供静态方式访问
    12     public static Properties configs = new Properties();
    13     static {
    14         //获取配置文件流
    15         InputStream in = Factory.class.getResourceAsStream("config.properties");
    16         try {
    17             //properties读取文件输入流
    18             configs.load(in);
    19         } catch (IOException e) {
    20             e.printStackTrace();
    21             //静态方法/块中的异常是捕获不到的
    22             throw new RuntimeException(e);
    23         }
    24     }
    25     public static Car getInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    26         //从配置文件中取出Car键的值:汽车类的全路径
    27         String carName = configs.getProperty("Car");
    28         //反射获取Class对象
    29         Class<?> clazz = Class.forName(carName);
    30         //反射新建实例
    31         Car car = (Car)clazz.newInstance();
    32         return car;
    33     }
    34     
    35 }

    以上代码是在这个Factory类被ClassLoader load的时候自动读取配置文件,并在配置文件中get(key)的方式获得key对应的value,查看Java docs文档可以看出Properties类是一种Map的实现,通过forName反射出我们需要的类的Class对象(在文件中查找我们需要的 类.class 文件),通过newInstance()方法获取该类的实例,相当于new,这样我们就能动态的通过修改配置文件,而无需修改代码,无需重新编译即可改变代码中的对象。

    下边是测试类

     1 package com.mi.simplefactory.simplefactory3;
     2 
     3 import com.mi.simplefactory.simplefactory1.Car;
     4 import com.mi.simplefactory.simplefactory2.Family;
     5 
     6 public class Test {
     7 
     8     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
     9         Family family = new Family();
    10         Car car = Factory.getInstance();
    11         family.setCar(car);
    12         family.travel();
    13     }
    14 }

    输出:

    打开配置文件第一行,关掉第二行

    全家出游!
    奔驰出行,请勿追尾
    玩的愉快

    打开配置文件第二行,关掉第一行

    全家出游!
    本田上路,请勿抛砖
    玩的愉快

    总结:

      简单工厂模式:

    1. 私有化工厂类的构造方法
    2. 根据配置文件的变化或者传参的变化,动态返回一个该参数代表的类的实例
    3. 拥有一个getInstance的方法
  • 相关阅读:
    移动传感器扫描覆盖
    最小生成树
    什么是壳 脱壳篇01
    最小生成树
    最小生成树
    最小生成树
    最小生成树
    最小生成树
    普里姆算法
    普里姆算法
  • 原文地址:https://www.cnblogs.com/hellxz/p/8449354.html
Copyright © 2011-2022 走看看