创建型模式、主要用于解决Java对象的创建问题
工厂模式 工厂模式的说明在面向对象的编程中,继承和多态的概念实现了父类与子类之间的(is-A)关系
基于这种关系实现了子类的多态性,这种抽象的方式为子类提供了相同的操作并且支持子类的功能性拓展。但是出现了这样的问题?
Verhicle verhicle = new Car();
Verhicle verhicle = new Truck();
problem所在:
子类复写了父类的方法,那么子类实例化父类对象时,就必须每一个子类都要进行。这样就造成了对于不同的子类要调用不同的构造器去实例化父类对象。缺乏统一性操作。
另外从上面的两行代码可以看出子类与父类之间的依赖关系、耦合度高
违反了父类的开闭原则和子类的单一职责原则
简单工厂模式的引入,实现逻辑的封装,使用公共的工厂类实现统一创建对象实例化父类的行为。
简单工厂模式简单工厂实现的三种方式
静态工厂模式
使用反射机制进行类注册
使用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方法进行类注册的简单工厂模式
只是基于上面反射机制进行类注册的思想进行了一个小的修改:
避免使用反射机制、提高性能
如何实现呢?
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图
解决方式:
服务端把产品接口化、对于所有需要拓展的产品可以直接实现统一接口方法,以及自定义方法。