简单工厂,工厂方法,抽象工厂模式

个人技术博客(IBLi)

CSDN Github
掘金

简单工厂模式

简单工厂模式是指有一个工厂对象决定创建出哪一个产品类的实例;属于创建型模式,但它不属于GOF 23种设计模式。

UML类图

组成要素

1、一个抽象产品类
2、具体产品类
3、一个工厂

肥宅喜爱的各种快乐水(产品接口)

public interface Kls {
    String name();
}
复制代码

肥宅快乐水-可乐(具体产品)

public class Coke implements Kls {
    @Override
    public String name() {
        return "肥宅快乐水-可乐";
    }
}
复制代码

快乐水-雪碧(具体产品)

public class Sprite implements Kls {
    @Override
    public String name() {
        return "快乐水-雪碧";
    }
}
复制代码

快乐水生产工厂(工厂类)

public class KlsFactory {
    public static Kls getFzs(String type) throws Exception {
        Kls fzs = null;
        if ("coke".equalsIgnoreCase(type)) {
            fzs = new Coke();
        } else if ("sprite".equalsIgnoreCase(type)) {
            fzs = new Sprite();
        }
        if (Objects.isNull(fzs)) {
            throw new RuntimeException("没找到快乐水~");
        }
        return fzs;
    }
}
复制代码

客户端使用

public class Fz {
    @Test
    public void drink() throws Exception {
        // 制造可乐
        Kls coke = KlsFactory.getFzs("coke");
        System.out.println("肥宅开始喝:" + coke.name());

        // 制造雪碧
        Kls sprite = KlsFactory.getFzs("sprite");
        System.out.println("肥宅开始喝:" + sprite.name());
    }
}

复制代码

简单工厂优缺点

优点

  • 对客户端隐藏的具体的实现,客户端只需要知道要创建什么对象即可,不用关心对象是怎么创建的
  • 解耦,客户端不需要通过new来创建对象,如果后期产品类需要修改,则只需要修改工厂类即可,不用整个项目遍地去寻找哪里有new

缺点

  • 由一个专门的工厂负责生产,如果业务变得复杂,这个类将变得十分臃肿
  • 工厂类生产什么产品都是写死在工厂中的,如果增加新的产品,还要修改工厂类的生产逻辑

工厂方法模式

工厂方法模式(Factory Method)是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。

组成要素

1、一个抽象产品类
2、多个具体产品类
3、一个抽象工厂
4、多个具体工厂 - 每一个具体产品对应一个具体工厂
5、符合 - OCP开放封闭原则

接着上面快乐水的例子。将 快乐水工厂 (KlsFactory) 抽象出共有方法,再分别实现具体的快乐水生产工厂。

快乐水总工厂

public interface Factory {
    /**
     * 制造快乐水
     *
     * @return Kls
     */
    Kls create();
}
复制代码

可乐工厂

public class CokeFactory implements Factory {
    @Override
    public Kls create() {
        return new Coke();
    }
}
复制代码

雪碧工厂

public class SpriteFactory implements Factory {
    @Override
    public Kls create() {
        return new Sprite();
    }
}
复制代码

肥宅(客户端)

public class Fz {
    @Test
    public void drink() throws Exception {
        // 制造可乐
        CokeFactory cokeFactory = new CokeFactory();
        Kls coke = cokeFactory.create();
        System.out.println("肥宅开始喝:" + coke.name());

        // 制造雪碧
        SpriteFactory spriteFactory = new SpriteFactory();
        Kls sprite = spriteFactory.create();
        System.out.println("肥宅开始喝:" + sprite.name());
    }
}
复制代码

扩展芬达快乐水

public class Fanta implements Kls {
    @Override
    public String name() {
        return "快乐水-芬达";
    }
}
复制代码

复制代码芬达工厂

public class FantaFactory implements Factory {
    @Override
    public Kls create() {
        return new Fanta();
    }
}
复制代码

肥宅使用添加

FantaFactory fantaFactory = new FantaFactory();
Kls fanta = fantaFactory.create();
System.out.println("肥宅开始喝:" + fanta.name());
复制代码

工厂方法模式优缺点

优点

1、降低了代码耦合度,对象的生成交给子类去完成(这里的耦合度是相对于简单工厂模式的工厂类比较的)
2、降低了代码耦合度,对象的生成交给子类去完成

缺点

1、增加了代码量,每个具体产品都需要一个具体工厂(在具体的业务中可能会产生大量的重复代码)
2、当增加抽象产品 也就是添加一个其他产品族 需要修改工厂 违背OCP

抽象工厂模式

组成要素

1、多个抽象产品类
2、具体产品类
3、抽象工厂类 - 声明(一组)返回抽象产品的方法
4、具体工厂类 - 生成(一组)具体产品

一个抽象产品类和两个具体的产品(可乐)

public abstract class Coke {
    public abstract void doCreate();
}

public class LocalCoke extends Coke{
    @Override
    public void doCreate() {
        System.err.println("生产本土可乐");
    }
}

public class ForeignCoke extends Coke{
    @Override
    public void doCreate() {
        System.out.println("生产外国可乐");
    }
}
复制代码

一个抽象产品类和两个具体的产品(雪碧)

public abstract class Sprite {
    public abstract void doCreate();
}

public class LocalSprite extends Sprite{
    @Override
    public void doCreate() {
        System.out.println("生产本地雪碧");
    }
}

public class ForeignSprite extends Sprite{
    @Override
    public void doCreate() {
        System.err.println("生产外国雪碧");
    }
}
复制代码

一个抽象工厂和两个具体的工厂

public interface IAbstractFactory {
   
    /**
     * 成产可乐
     *
     * @return 声明(一组)返回抽象产品的方法
     */
    Coke createCoke();

    /**
     * 生产雪碧
     *
     * @return 声明(一组)返回抽象产品的方法
     */
    Sprite createSprite();
}

public class LocalFactory implements IAbstractFactory{
    
    /**
     * 成产可乐
     *
     * @return 生成(一组)具体产品  
     */
    @Override
    public LocalCoke createCoke() {
        return new LocalCoke();
    }

    /**
     * 生产雪碧
     *
     * @return 生成(一组)具体产品  
     */
    @Override
    public LocalSprite createSprite() {
        return new LocalSprite();
    }
}

public class ForeignFactory implements IAbstractFactory{
    /**
     * 成产可乐
     *
     * @return 生成(一组)具体产品  
     */
    @Override
    public ForeignCoke createCoke() {
        return new ForeignCoke();
    }

    /**
     * 生产雪碧
     *
     * @return 生成(一组)具体产品  
     */
    @Override
    public ForeignSprite createSprite() {
        return new ForeignSprite();
    }
}
复制代码

抽象工厂的使用

public class FactoryTest {
    public static void main(String[] args) {
        LocalFactory localFactory = new LocalFactory();
        LocalCoke localCoke = localFactory.createCoke();
        localCoke.doCreate();

        ForeignFactory foreignFactory = new ForeignFactory();
        ForeignSprite foreignSprite = foreignFactory.createSprite();
        foreignSprite.doCreate();
    }
}
复制代码

抽象工厂的优缺点

优点

1、代码解耦
2、很好的满足OCP开放封闭原则
3、抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类 对于复杂对象的生产相当灵活易扩展
(相对于工厂方法模式的优化)

缺点

1、扩展产品是需要修改所有工厂,违反违反OCP原则
2、整体实现也比较复杂

参考文章

还有多少个十年 继续做热血少年