美文网首页@IT·互联网java架构经验分享
面试官:小伙子,够了够了,一个工厂模式你都在这说半个小时了!

面试官:小伙子,够了够了,一个工厂模式你都在这说半个小时了!

作者: 前程有光 | 来源:发表于2020-12-27 21:19 被阅读0次

前言

创建型模式、主要用于解决Java对象的创建问题

工厂模式

工厂模式的说明

在面向对象的编程中,继承和多态的概念实现了父类与子类之间的(is-A)关系

基于这种关系实现了子类的多态性,这种抽象的方式为子类提供了相同的操作并且支持子类的功能性拓展。但是出现了这样的问题?

Verhicle verhicle = new Car();

Verhicle verhicle = new Truck();

problem所在

  1. 子类复写了父类的方法,那么子类实例化父类对象时,就必须每一个子类都要进行。这样就造成了对于不同的子类要调用不同的构造器去实例化父类对象。缺乏统一性操作
  2. 另外从上面的两行代码可以看出子类与父类之间的依赖关系、耦合度高
  3. 违反了父类的开闭原则子类的单一职责原则

简单工厂模式的引入,实现逻辑的封装,使用公共的工厂类实现统一创建对象实例化父类的行为。

简单工厂模式

  • 简单工厂实现的三种方式
    1. 静态工厂模式
    2. 使用反射机制进行类注册
    3. 使用newInstance方法进行类注册

简单工厂的UML图

  • 静态工厂模式的解决方式

创建一个单独的verhicle简单工厂类。通过内置枚举储存所有需要创建实例的子类,并通过统一的create(type)方法根据传入参数的类型实现按需创建实例。

public class VerhicleFactory {
    public enum VerhicleType {
        Car,Truck,Boat;
    }

    public static Verhicle create(VerhicleType type) {
        if(type.equals(VerhicleType.Car)) {
            return new Car();
        }
        if(type.equals(VerhicleType.Truck)) {
            return new Truck();
        }
        if(type.equals(VerhicleType.Boat)) {
            return new Boat();
        }
        else return null;
    }
}

优势

这种额外使用工厂类的方式,解决了上面子类实例化父类的破坏单一职责原则、实现了构造实例的统一性操作。

缺点

可以从存储的枚举看出,一旦新增拓展的子类就必须修改工厂的枚举,破坏了工厂类自身的开闭原则。

仍然没有解决父类的对内关闭的对外拓展的开闭原则。

  • 使用反射机制进行类注册的解决方式

为了解决静态工厂模式破坏自身开闭原则的弊端、我们可以使用反射机制使得注册的新类在使用时被实例化。从而保证了对外拓展开发,对内修改闭合。也就是说即使新增对父类拓展的子类,也不再重新修改静态工厂内的枚举。

//服务端

public class Product {/*类体内容*/}
public class Product1 extends Product {}
/*...更多的拓展子类...*/
public class MoreProducts extends Product {}

/*使用反射机制进行类注册的简单工厂模式*/

private Map<String,Class> registeredProduct = new 
    HashMap<String,Class>();

/**实现对拓展子类的注册、所有的拓展子类将会被记录在Map集合中
 *@parameter
 * productId子类ID也就是子类的类型,对应静态工厂的枚举类型
 * productClass子类的类对象,也就是子类的Class对象
 */
public void registerProduct(String productId, Class productClass) {
    registeredProduct.put(productId, productClass);
}

/**更具传入的子类类型、构造对应的子类实例并返回
 *@parameter
 * ProductType子类类型和上面的子类ID一致,对应静态工厂的枚举类型
 */
public Product createProduct(String ProductType) throws InstantiationException,IllegalAccessException {
    Class productClass = registeredProduct.get(ProductType);
    return (Product) productClass.newInstance();
}

//客户端就依据相应的方法,进行类的注册和实例创建

优点

解决了静态工厂类破坏开闭原则的弊端,把注册和创建实例分开实现注册的类在使用时才实例化。

缺点

反射机制影响了程序性能、使用多了的话,程序性能肯定要低效很多。

  • 使用newInstance方法进行类注册的简单工厂模式

只是基于上面反射机制进行类注册的思想进行了一个小的修改

  1. 避免使用反射机制、提高性能
  2. 如何实现呢?
    • Map集合中不在存储Class对象,而是已经创建的子类实例
  • 基类中创建一个抽象方法
  • 子类全部复写、方法体是创建子类对象
    • 这样就可以实现上面Map集合存储的时已经创建的子类实例
//服务端

public abstract class Product {
    Product newInstance();
}
public class Product1 extends Product {}
/*...更多的拓展子类...*/
public class MoreProducts extends Product {
    @override
    public  MoreProducts newInstance() {
        return new MoreProducts();
    }
}

/*使用反射机制进行类注册的简单工厂模式*/

private Map<String,Product> registeredProduct = new 
    HashMap<String,Product>();

/**实现对拓展子类的注册、所有的拓展子类将会被记录在Map集合中
 *@parameter
 * productId子类ID也就是子类的类型,对应静态工厂的枚举类型
 * productClass子类的类对象,也就是子类的Class对象
 */
public void registerProduct(String productId, Product productType) {
    registeredProduct.put(productId, productType);
}

/**更具传入的子类类型、构造对应的子类实例并返回
 *@parameter
 * ProductType子类类型和上面的子类ID一致,对应静态工厂的枚举类型
 */
public Product createProduct(String ProductId) throws InstantiationException,IllegalAccessException {
    Product productType  = registeredProduct.get(ProductId);
    return (Product) productType.newInstance();
}

//客户端就依据相应的方法,进行类的注册和实例创建

优点

把基类之间划为抽象类,解决了父类的开闭原则和子类的单一职责原则。支持了创建对象的统一性操作。

缺点

类之间的继承关系造成代码依然耦合度高的问题。

仍然存在未实现父类对内修改闭合的风险。

工厂方法模式

工厂方法模式的UML图

image

解决方式:

  1. 服务端把产品接口化、对于所有需要拓展的产品可以直接实现统一接口方法,以及自定义方法。

  2. 另外抽象化工厂、可以将产品的服务化功能集成在抽象工厂,并且内置构造实例的抽象方法。那么所有的拓展产品的工厂类都可以继承实现对应的构造方法和功能。

//  sever
public interface Product{
    void features();      //定义统一的功能
}
public class Product1 implements Product {/*实现统一接口方法、以及自定义方法*/}
public class MoreProducts implements Product {/*实现统一接口方法、以及自定义方法*/}

/*工厂方法*/

public abstract class AbastractFactory {
    Product create();        //定义统一构造器
    void sever(){/*相应的统一服务功能*/}
}
public class Product1Factory implements AbstractFactory {/*实现构造器*/}
public class MoreProductsFactory extends AbstractFactory {/*实现构造器*/}

优势:

将产品解耦,并且每一个拓展产品都有相应的工厂类实现对应的构造实例以及服务功能

缺点:

易造成工厂的冗余、拓展产品过多时出现工厂类增多。

抽象工厂模式

解决方法:

在工厂方法模式的基础之上、在抽象工厂中不再单独创建统一的构造器,而是创建一类或者所有的拓展产品构造器。这样工厂类继承的时候只需要少了的继承就可以完成多个拓展产品的构造任务。

//  sever
public interface Product{
    void features();     //定义统一的功能
}
public class Product1 implements Product {/*实现统一接口方法、以及自定义方法*/}
public class MoreProducts implements Product {/*实现统一接口方法、以及自定义方法*/}

/*抽象工厂模式*/

public abstract class AbastractFactory {
    Product createProduct1();        //定义Product1构造器
    Product createMoreProducts();    //定义MoreProducts构造器
    void sever(){/*相应的统一服务功能*/}
}

public class ProductFactory extends AbstractFactory {/*实现对应构造器*/}

优点:

减少了工厂类的数量、避免冗余问题

最后

欢迎关注公众号:前程有光,领取一线大厂Java面试题总结+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结!

相关文章

  • 面试官:小伙子,够了够了,一个工厂模式你都在这说半个小时了!

    前言 创建型模式、主要用于解决Java对象的创建问题 工厂模式 工厂模式的说明 在面向对象的编程中,继承和多态的概...

  • 面试官:够了够了,一个工厂模式你都在这说半个小时了

    创建型模式、主要用于 解决Java对象的创建问题 工厂模式 工厂模式的说明 在面向对象的编程中,继承和多态的概念实...

  • 工厂模式

    工厂模式——看这一篇就够了 简单工厂模式: 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以...

  • 老乡?博导。

    昨天同事吐槽说前天晚上到家都半夜了。 我们说你不是走得很早吗,地铁一个小时足够了啊? 同事说:“你们不知道,我那同...

  • 曾经的上班日记

    换工作后的第一天 今天真是体验了真正上班族的恐怖。本来一个小时的时间,心想坐公交车半个小时应该够了,然后半个小时慢...

  • 不仅仅是喜欢。

    你不必太在意。 我心里认可你,就够了。足够了。 在这年纪遇见你。 可能用光了我所有的运气~ 虽然说,承诺对我来说很...

  • 孩子,今天你哭了吗?

    “哭哭哭,你给我哭够了再回来!” “你哭是吧?哭够半个小时去!” “小祖宗啊,你怎么总是哭啊!” …………. 这些...

  • 睡嗨了

    我们都知道午睡的时间大概半个小时就足够了,就可以保证下午的学习和工作有一个不错的状态了。因为睡得时间如果过长,就容...

  • 我不要暴躁的妈妈,我要温柔的妈妈

    “有完没完了,都多大了还哭,有点事就哭,最近你是怎么了?还没有小时候听话懂事,你就自己在这屋哭吧,什么时候哭够了什...

  • 丢了就是丢了

    “喜欢就够了,还能联系上就够了,在彼此心里待过就够了,你在这世上平平安安就够了,其实在不在一起真的没那么重要了.....

网友评论

    本文标题:面试官:小伙子,够了够了,一个工厂模式你都在这说半个小时了!

    本文链接:https://www.haomeiwen.com/subject/llxanktx.html