哇塞!这么全的工厂模式你见过吗

设计模式二–工厂模式

举例:

女娲采集黄土捏成人的形状,然后放到八卦炉中烧制,然后放到土地上生长,但是意外随时都会发生。

  • 第一次烤人,感觉应该熟了,往地上一放,哇,没烤熟,白人诞生了。
  • 第二次烤人,上一次没有烤熟,这次多烤一会,放到世间一看,哇,熟过头了,于是黑人诞生了。
  • 第三次烤人,一边烧制一遍看,知道表皮发黄,嘿,刚刚好,于是黄种人诞生了。

思考:

  • 在面向对象编程的思想中,万物皆对象。于是我们抽象出具体的三个对象。
  • 女娲,八卦炉,三种不同肤色的人。
  • 女娲可以用场景类Client来表示,八卦炉可以用工厂来表示,三个不同肤色的人,他们都是同一个接口下面的不同实现类。
    于是我们生成类图。
    在这里插入图片描述
  • AbstarctHummanFactory是一个抽象类,HumanFactoruy是一个实现类,完成具体的任务,创建人类。Human是人类- 总称,三个人种是其实现类,Nawa是一个场景,负责模拟这个场景,发起任务。

人类接口

/**
 * @atuhor sha1024
 */
public interface Human {
    void getTalk();
    void getColor();
}

白人人类

/**
 * @atuhor sha1024
 */
public class WhiteHuman implements Human{

    @Override
    public void getTalk() {
        System.out.println("我是一个白人");
    }

    @Override
    public void getColor() {
        System.out.println("我的皮肤是白色的");
    }
}

黄色人种

/**
 * @atuhor sha1024
 */
public class YellowHuman implements Human{

    @Override
    public void getTalk() {
        System.out.println("黄种人说话最好听");
    }

    @Override
    public void getColor() {
        System.out.println("我的皮肤是黄色的");
    }
}

黑色人种

/**
 * @atuhor sha1024
 */
public class BlackHuman implements Human{

    @Override
    public void getTalk() {
        System.out.println("黑人说话听不懂");
    }

    @Override
    public void getColor() {
        System.out.println("我的皮肤是黑色的");
    }
}

定义一个抽象工厂,定义了一个泛型实现了Human

/**
 * @atuhor sha1024
 */
public abstract  class AbstarctHummanFactory {
    public abstract <T extends  Human> T createHuman(Class<T> c);
}
定义了一个人类工厂实现抽象人类工厂
public class HummanFactory extends AbstarctHummanFactory {
    @Override
    public <T extends Human> T createHuman(Class<T> c) {
        //定义一个人种
        Human human = null;
        try{
            human = (T)Class.forName(c.getName()).newInstance();
        }catch (Exception e){
            throw new RuntimeException("定义人种错误");
        }

        return (T)human;
    }
}

女娲类,实现具体的场景

public static void main(String[] args) {
    AbstarctHummanFactory  hummanFactory = new HummanFactory();
    Human whiteHuman = hummanFactory.createHuman(WhiteHuman.class);
    whiteHuman.getColor();
    whiteHuman.getTalk();
    Human blackHuman = hummanFactory.createHuman(BlackHuman.class);
    blackHuman.getTalk();
    blackHuman.getColor();
    Human yellowHuman = hummanFactory.createHuman(YellowHuman.class);
    yellowHuman.getColor();
    yellowHuman.getTalk();
    SpringApplication.run(FactoryApplication.class, args);
}

执行结果
在这里插入图片描述

工厂方法模式的定义

  • 定义一个用于创建对象的接口,让子类来决定实例化哪一个。工厂方法使一个类的实例化延迟到其子类。
    在这里插入图片描述

在工厂模式中,抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义;Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreateCreator完成的。
具体的产品类可以有多个,都继承抽象产品类

/**
 * 抽象产品类
 * @atuhor sha1024
 */
public abstract class Product {
    //产品类的公共方法
    public void method1(){
        System.out.println("我是抽象工厂方法1");
    }

    /**
     * 抽象方法
     */
    public abstract void method2();
}

产品类1

/**
 * @atuhor sha1024
 */
public class ConcreateProduct1 extends Product {
    @Override
    public void method2() {
        /**
         * 具体业务逻辑
         */
    }
}

产品类2

/**
 * @atuhor sha1024
 */
public class ConcreateProduct2 extends Product {
    @Override
    public void method2() {
        /**
         * 业务逻辑
         */
    }
}

抽象工厂

/**
 * @atuhor sha1024
 */
public abstract class Creator {
    /**
     * 创建一个产品对象,其输入任何参数类型都可以自行设置
     * 通常为String,Enum,Class,也可以为空
     */
    public abstract <T extends Product> T createProduct(Class<T> c);
}

具体如何产生一个产品对 对象是由具体的工厂实现类来决定的

/**
 * 通过发射获取到实例
 * @atuhor sha1024
 */
public  class ConcreateCreator  extends Creator{
    @Override
    public <T extends Product> T createProduct(Class<T> c) {
        Product product = null;
        try{
            product = (T)Class.forName(c.getName()).newInstance();
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
        return (T)product;
    }
}

场景类

/**
 * @atuhor sha1024
 */
public class Client {
    public static void main(String[] args){
        Creator creator = new ConcreateCreator();
        Product product = creator.createProduct(ConcreateProduct1.class);
        /**
         * 业务逻辑
         */
        product.method2();
    }
}

工厂模式的优点:

  • 良好的封装性,代码结果清晰。
  • 工厂方法模式的扩展性非常好。
  • 屏蔽产品类,产品类如何变化,调用者不用关心,它只需要关心产品的接口。更好的实现了解耦合。

工厂方法模式使用场景

  • 工厂方法是new一个对象的 替代品,所以在所有需要生成对象的地方都可以使用,但是要考虑是否要增加一个产品类来增加代码的复杂性。
  • 需要灵活的可扩展的框架时,可以考虑采用工厂方法模式。

工厂模式的扩展

缩小为简单工厂模式

在这里插入图片描述
上图中我们去掉了AbstarctHummanFactory
抽象人类工厂,同时把createHuman改为静态类型。

/**
 * @atuhor sha1024
 */
public class NvWa {
    public static void main(String[] args){
        Human human = HummanFactory2.createHuman(YellowHuman.class);
        Human human2 = HummanFactory2.createHuman(BlackHuman.class);
    }
}

运行结果没用发生变化,但是我们的类图变得更加简单了,因为简单所以我们称为简单工厂模式

升级为多个工厂模式

在这里插入图片描述
当我们在做一个复杂项目的时候,经常会遇到初始化一个对象很费力的情况,所有产品都放到一个工厂方法中进行初始化会使代吗结构不清晰。例如:一个产品类有5个具体实现类,每个实现类的初始化方法都不相同,如果写在工厂中,会导致该方法巨大无比。
考虑到要结构清晰,我们就为每个产品定义一个创造者,然后由调用者去选择与哪个工厂方法关联。

定义一个抽象工厂

public abstract  class AbstarctHummanFactory {
    public abstract Human createHuman();
}

黑人人种创建工厂

public class BlackHummanFactory extends AbstarctHummanFactory {
    @Override
    public Human createHuman() {
        return new BlackHuman();
    }
}

黄色人种创建工厂

public class YellowHummanFactory extends AbstarctHummanFactory {
    @Override
    public Human createHuman() {
        return new YellowHuman();
    }
}

场景类

public static void main(String[] args){
    Human yellowHuman = (new YellowHummanFactory()).createHuman();
    yellowHuman.getTalk();
    yellowHuman.getColor();
    Human blackHuman = (new BlackHummanFactory()).createHuman();
    blackHuman.getTalk();
    blackHuman.getColor();
}

运行结果还是相同的,每一个产品类都对应了一个创建类好处就是创建类职责清晰,而且结构简单,但是给可扩展性和维护性带来了一定的影响。

当然,在复杂的应用场景中一般采用多工厂模式,然后增加一个协调类,避免调用者和各个子工厂交流,对高层模块提供统一调用api。

替代单例模式

在这里插入图片描述
Singleton定义了一个private 的无参构造函数,目的是不允许通过new 的方式创建一个对象

public class Singleton {
    private Singleton(){}
    public void doSomeThing(){
        //业务逻辑
    }
}

单例类,Singleton保证不能通过正常情况下建立一个对象,只能通过反射方式创建

public class SingletonFactory {
    private static Singleton singleton;
    static {
        try{
            Class c1 = Class.forName(Singleton.class.getName());
            //获取无参构造函数
            Constructor constructor = c1.getDeclaredConstructor();
            //设置无参是可访问的
            constructor.setAccessible(true);
            //产生一个实例对象
            singleton = (Singleton) constructor.newInstance();
        }catch(Exception e){

        }
    }
   public static Singleton getSingleton(){
        return singleton;
   }

通过获得类构造器,然后设置访问权限,生成一个对象,然后提供外部访问,保证内部中的对象唯一。当然,其他的类也能通过反射的方式获得一个单例对象。

延迟初始化

在这里插入图片描述
ProductFactory负责产品类对象的创建,并通过prMap创建一个缓存,对需要被重用的对象保留

public class ProductFactory {
    private static final Map<String,Product> prMap = new HashMap<>();
    public static synchronized Product createProduct(String type) throws Exception{
        Product product = null;
        //判断缓存中是否有这个对象
        if(prMap.containsKey(type)){
            product = prMap.get(type);
        }else{
            if(type.equals("Product1")){
                product = new ConcreateProduct1();
            }else{
                product = new ConcreateProduct2();   
            }
            //同时缓存数据到prMap中
            prMap.put(type,product);
        }
        return product;
    }
}

通过定义一个Map容器,容纳所有对象,如果Map容器中已经有的对象,则直接取出;如果没用,则根据需要的类型产生一个对象并放入到Map容器中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章