java设计模式-工厂模式与抽象工厂模式

82 阅读3分钟

工厂模式

工厂模式是一种建造模式,可以避免用户在任意new对象的条件下完成实例的创建。

简单工厂模式

public class FoodFactory {
    public static Food makeFood(String name) {
        if (name.equals("Noodle")) {
            Food noodle = new Noodle();
            noodle.salt();
            return noodle;
        } else if (name.equals("Dumplings")) {
            Food chicken = new Dumplings();
            chicken.vinegar();
            return chicken;
        } else {
            return null;
        }
    }
}

如上述代码所示,当我们需要制作食物的时候,就可以调用FoodFactory的静态方法,创造对应的食物。

根据单一职责原则,通常XxxFactory的职责就是创造Xxx,比如FoodFactory的职责就是创造Food。

工厂模式

虽然简单工厂模式可以解决一些问题,但是可以看到它仍有一些问题。

比如如果我要做一台电脑。电脑制作过程中可以输入参数比如CPU性能,内存性能,硬盘性能等等。

但是在此之前,我首先要考虑,我的电脑使用AMD厂商还是Intel厂商。

因此我们可以创建一个AMD工厂和一个Intel工厂,他们都可以继承一个computer工厂的父类。

public interface ComputerFactory {
    public Computer getComputer(Double cpu,Integer ram,Integer hdd);
}
class AMDFactory implements ComputerFactory{
​
    @Override
    public Computer getComputer(Double cpu,Integer ram,Integer hdd) {
        return new AMDComputer(cpu,ram,hdd);
    }
}
class IntelFactory implements ComputerFactory{
​
    @Override
    public Computer getComputer(Double cpu,Integer ram,Integer hdd) {
        return new IntelComputer(cpu,ram,hdd);
    }
}

我们看客户端调用的时候的输出:

class client{
    public static void main(String[] args) {
        //选择工厂
        ComputerFactory computerFactory1 = new AMDFactory();
        Computer computer1 = computerFactory1.getComputer(2.4, 16, 2);
        System.out.println(computer1);
​
        //选择工厂
        ComputerFactory computerFactory2 = new IntelFactory();
        Computer computer2 = computerFactory2.getComputer(2.9, 8, 1);
        System.out.println(computer2);
    }
}
​
AMD computer{cpu=2.4GHz, ram=16GB, hdd=2TB}
Intel computer{cpu=2.9GHz, ram=8GB, hdd=1TB}

类关系如图:

image.png

一个典型的例子

我们使用日志工厂的时候,首先要指定日志工厂的实现类。

比如FileLogFactory 和 KafkaLogFactory,他们都继承了 LogFactory接口。

抽象工厂模式

抽象工厂模式是对工厂模式地一个拓展。

在引入抽象工厂模式的开始,首先介绍产品族的概念,比如华为手机、华为耳机、华为手表都是一共产品族的产品。苹果手机、苹果耳机、苹果手表都是另一产品族的产品。我们可以认为相同产品族的产品的适配性更好,甚至不是统一产品族的产品可以无法相互兼容使用,因而在客户端调用的时候我们希望客户端可以方便地创造同一族的产品。

因而可以在工厂上进行拓展,使得每一个工厂都可以实现同一族不同产品的建造。

image.png

客户端:

public class AbstractFactory {
    public static void main(String[] args) {
        PhoneFactory phoneFactory = new HuaweiFactory();
        System.out.printf(phoneFactory.getPone().toString());
        System.out.printf(phoneFactory.getHeadset().toString());
        System.out.printf(phoneFactory.getWatch().toString());
    }
}

工厂:

interface PhoneFactory{
    Phone getPone();
    Headset getHeadset();
    Watch getWatch();
}
class HuaweiFactory implements PhoneFactory{
​
    @Override
    public Phone getPone() {
        return new Phone("mate60");
    }
​
    @Override
    public Headset getHeadset() {
        return new Headset("FreeBuds");
    }
​
    @Override
    public Watch getWatch() {
        return new Watch("GT3");
    }
}
class AppleFactory implements PhoneFactory{
    @Override
    public Phone getPone() {
        return new Phone("iphone");
    }
​
    @Override
    public Headset getHeadset() {
        return new Headset("AirPods");
    }
​
    @Override
    public Watch getWatch() {
        return new Watch("Apple Watch");
    }
}

优劣分析

优点:

  • 符合依赖抽象原则
  • 简化调用者可以方便知道产品族

缺点

  • 产品族难扩展,修改一个产品需要所有工厂都完成扩展
  • 增加了系统的抽象性和理解难度;