工厂模式-Java&Kotlin
概念:
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。它提供了一种创建对象的最佳方式,属于创建型模式。
类型:
工厂模式一般有两类,工厂方法模式和抽象工厂模式。平时编写的时候也有一种简单工厂模式,但是它不属于23种设计模式,更像是一种编程习惯。
具体实现:
1、简单工厂:
案例简介:一个简单的生产手机的工厂,首先有一个手机的抽象类(Phone),让不同品牌的手机继承该类,华为手机(HuaWeiPhone)、小米手机(XiaoMiPhone)。一个简单工厂用来生产手机(SimpleFactory)。
public abstract class Phone {
abstract String getName();
}
public class HuaWeiPhone extends Phone {
@Override
String getName() {
return "华为手机";
}
}
public class XiaoMiPhone extends Phone {
@Override
String getName() {
return "小米手机";
}
}
public class SimpleFactory {
public static Phone createPhone(String type){
Phone phone;
switch (type) {
case "HuaWei":
phone = new HuaWeiPhone();
break;
case "XiaoMi":
phone = new XiaoMiPhone();
break;
default:
throw new RuntimeException("没有该牌子手机");
}
return phone;
}
}
public class TestSimpleFactory {
public static void main(String[] args) {
// Phone phone = SimpleFactory.createPhone("HuaWei");
Phone phone = SimpleFactory.createPhone("XiaoMi");
System.out.println(phone.getName());
}
}
SimpleFactory 简单工厂创建方法可以static修饰,也称静态工厂。
优点:该类封装了创建对象的过程,可以通过参数直接获取对象,把对象的创建和业务逻辑层分开,这样以后避免了修改业务代码,如果要实现新产品直接修改工厂类,降低了业务代码修改的可能性,更加容易扩展。
缺点:增加新产品还是需要修改工厂类的代码,违背了"开闭原则"。
2、工厂方法模式:
案例简介:还是同样的生产手机的案例,定义一个用于创建对象的接口(一个工厂接口),让工厂子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类中。具体实现代码如下:
public abstract class Phone {
abstract String getName();
}
public class HuaWeiPhone extends Phone {
@Override
String getName() {
return "华为手机";
}
}
public class XiaoMiPhone extends Phone {
@Override
String getName() {
return "小米手机";
}
}
上述产品类信息没有改变
//工厂接口,将创建方法实现到具体工厂类中
public interface Factory {
Phone createPhone();
}
//华为手机工厂
public class HuaWeiFactory implements Factory {
@Override
public Phone createPhone() {
return new HuaWeiPhone();//创建华为手机对象
}
}
//小米手机工厂
public class XiaoMiFactory implements Factory {
@Override
public Phone createPhone() {
return new XiaoMiPhone();//创建小米手机对象
}
}
//测试具体工厂创建的实例
public class Test {
public static void main(String[] args) {
// Phone phone = new HuaWeiFactory().createPhone();
Phone phone = new XiaoMiFactory().createPhone();
System.out.println(phone.getName());
}
}
本案例中增加了工厂接口Factory,意为让具体实现工厂创建相应的对象
优点: 用户只需要知道具体工厂名称就可得到所要的产品,无需知道产品的具体创建过程;在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无需对原工厂进行任何修改,满足开闭原则。
缺点:每增加一个产品就需要增加一个具体产品类和一个对应的具体工厂类,增加系统的复杂度 (类爆炸)。
2、抽象工厂模式:
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
场景:考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族。
(笔记本 台式机 一体机 属于同一级别)
(华为笔记本 华为手机 华为一体机 同一产品族)
还是生产手机的案例,增加同级产品手表,以kotlin代码为例:
//手机抽象类
abstract class Phone {
abstract fun getName(): String
}
//华为手机
class HWPhone : Phone() {
override fun getName(): String {
return "华为手机"
}
}
//小米手机
class XMPhone :Phone() {
override fun getName(): String {
return "小米手机"
}
}
//手表抽象类
abstract class Watch {
abstract fun getName(): String
}
class XMWatch :Watch(){
override fun getName(): String {
return "小米手表"
}
}
class HWWatch : Watch() {
override fun getName(): String {
return "华为手表"
}
}
//超级工厂
interface BaseFactory {
fun createPhone(): Phone
fun createWatch(): Watch
}
//华为工厂 生产华为手机、华为手表
class HuaWeiFactory :BaseFactory {
override fun createPhone(): Phone {
return HWPhone()
}
override fun createWatch(): Watch {
return HWWatch()
}
}
//小米工厂 生产小米手机、小米手表
class XiaoMiFactory :BaseFactory{
override fun createPhone(): Phone {
return XMPhone()
}
override fun createWatch(): Watch {
return XMWatch()
}
}
//测试方法
fun main(args: Array<String>) {
// var factory = HuaWeiFactory()
var factory = XiaoMiFactory()
var phone = factory.createPhone()
var watch = factory.createWatch()
println("${phone.getName()} ${watch.getName()}")
}
BaseFactory超级工厂,其中小米工厂XiaoMiFactory和华为工厂HuaWeiFactory都是围绕它创建的。具体工厂类,实现生产同一族的对象方法。
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。如果再添加一个产品族的话(比如添加一个oppo品牌),只需要添加对应的工厂类即可,不需要修改其他类,满足开闭原则。
缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
知识扩展:
通过Properties配置文件的方式,利用反射将简单工厂进行解耦。在工厂类中加载配置文件中的全类名,并创建对象进行存储,如果需要对象,直接进行获取即可。
public abstract class Phone {
abstract String getName();
}
public class HuaWeiPhone extends Phone {
@Override
String getName() {
return "华为手机";
}
}
public class XiaoMiPhone extends Phone {
@Override
String getName() {
return "小米手机";
}
}
配置文件 xxx.properties
xiaomi=包名.XiaoMiPhone
huawei=包名.HuaWeiPhone
工厂类实现:
public class PhoneFactory {
//1定义容器存储Phone对象
private static Map<String, Phone> map = new HashMap<>();
//2加载配置文件,只加载一次
static {
try {
//2.1创建Properties对象
Properties properties = new Properties();
//2.2调用load方法进行加载
InputStream resourceAsStream = PhoneFactory.class.getClassLoader().getResourceAsStream("xxx.properties");
properties.load(resourceAsStream);
//2.3遍历通过反射获取对象并存储到map中
Set<Object> keys = properties.keySet();
for (Object key : keys) {
String property = properties.getProperty((String) key);
Phone phone = (Phone) Class.forName(property).newInstance();
map.put((String) key, phone);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static Phone createPhone(String name) {
return map.get(name);
}
}
public class Test {
public static void main(String[] args) {
// Phone phone = PhoneFactory.createPhone("xiaomi");
Phone phone = PhoneFactory.createPhone("huawei");
System.out.println(phone.getName());
}
}