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

一个类里使用其他类,最常用的方式是 new 一个对象,这属于一种硬编码。每new 一个对象,增加了类与类之间的联系,不利于程序的松耦合。

在这里插入图片描述

简单工厂模式

public class FruitFactory {
    public Fruit create(String type){
        switch (type){
            case "苹果":
                AppleSeed appleSeed = new AppleSeed();
                Sunlight sunlight = new Sunlight();
                Water water = new Water();
                return new Apple(appleSeed, sunlight, water);
            case "梨子": return new Pear();
            default: throw new IllegalArgumentException("暂时没有这种水果");
        }
    }
}

public class User {
    private void eat(){
        FruitFactory fruitFactory = new FruitFactory();
        Fruit apple = fruitFactory.create("苹果");
        Fruit pear = fruitFactory.create("梨子");
        apple.eat();
        pear.eat();
    }
}

好处

1、将构建过程封装的好处不仅可以 降低耦合
2、如果某个产品构造方法相当复杂,使用工厂模式可以大大减少代码重复

弊端:

1、一是如果需要生产的产品过多,此模式会导致 工厂类过于庞大,承担过多的职责,变成超级类。当苹果生产过程需要修改时,要来修改此工厂。梨子生产过程需要修改时,也要来修改此工厂。也就是说这个类不止一个引起修改的原因。违背了单一职责原则
2、二是当要生产新的产品时,必须在工厂类中添加新的分支。而开闭原则告诉我们:类应该对修改封闭。我们希望在添加新功能时,只需增加新的类,而不是修改既有的类,所以这就违背了开闭原则

在这里插入图片描述

工厂方法模式

Gof原文:

Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.

为了解决简单工厂模式的这两个弊端

public interface IFactory {
	# 不同方法 类比 产品等级结构
    Fruit create();
}

# 实现类 类比 产品族
public class AppleFactory implements IFactory {
    @Override
    public Fruit create(){
        return new Apple();
    }
}

public class PearFactory implements IFactory {
    @Override
    public Fruit create(){
        return new Pear();
    }
}

public class User {
    private void eat(){
        IFactory appleFactory = new AppleFactory();
        Fruit apple = appleFactory.create();
        
        IFactory pearFactory = new PearFactory();
        Fruit pear = pearFactory.create();
        
        apple.eat();
        pear.eat();
    }
}
# 接口制定规则,规定所有Model都要有build方法
public interface ITeacher {
    void build();
}

# 定义Model
public class ChineseTeacher implements ITeacher {
    @Override
    public void build() {
        System.out.println("Build ChineseTeacher");
    }
}
public class MathTeacher implements ITeacher {
    @Override
    public void build() {
        System.out.println("Build MathTeacher");
    }
}

# 抽象类是抽取所有工厂都具有的能力,为了不重复提取出抽象方法
# create所有方法都有,createTeacher交给工厂灵活实现
public abstract class TeacherFactory {
    public ITeacher create() {
        ITeacher teacher = createTeacher();
        teacher.build();
        return teacher;
    }
    protected abstract ITeacher createTeacher();
}
public class ChineseTeacherFactory extends TeacherFactory {
    @Override
    protected ITeacher createTeacher() {
        return new ChineseTeacher();
    }
}
public class MathTeacherFactory extends TeacherFactory {
    @Override
    protected ITeacher createTeacher() {
        return new MathTeacher();
    }
}

# 使用
TeacherFactory chineseTeacherFactory = new ChineseTeacherFactory();
ChineseTeacher iTeacher = (ChineseTeacher) chineseTeacherFactory.create();
System.out.println(iTeacher.getClass());

TeacherFactory mathTeacherFactory = new MathTeacherFactory();
MathTeacher iTeacher1 = (MathTeacher) mathTeacherFactory.create();
System.out.println(iTeacher1.getClass());

在这里插入图片描述

工厂方法模式解决了简单工厂模式的两个弊端。
1、 当生产的产品种类越来越多时,工厂类不会变成超级类。工厂类会越来越多,保持灵活。不会越来越大、变得臃肿。如果苹果的生产过程需要修改时,只需修改苹果工厂。梨子的生产过程需要修改时,只需修改梨子工厂。符合单一职责原则。
2、当需要生产新的产品时,无需更改既有的工厂,只需要添加新的工厂即可。保持了面向对象的可扩展性,符合开闭原则。

工厂方法模式在Logback源码中的应用

Logback中已经分离出不同工厂负责创建不同日志框架,如Substitute日志框架、NOP日志框架、Log4J日志框架
在这里插入图片描述
在这里插入图片描述

抽象工厂模式

Gof原文

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

产品等级结构(Product Hierarchy)产品族(Product Family)是设计模式中的概念,特别是抽象工厂模式(Abstract Factory Pattern)中使用的重要术语。

在这里插入图片描述

# 接口制定规则,规定所有Model都要有build方法
public interface ITeacher {
    void build();
}
public interface ITutor {
    void build();
}

# 定义Model
public class ChineseTeacher implements ITeacher {
    @Override
    public void build() {
        System.out.println("Build ChineseTeacher");
    }
}
public class MathTeacher implements ITeacher {
    @Override
    public void build() {
        System.out.println("Build MathTeacher");
    }
}
public class ChineseTutor implements ITutor {
    @Override
    public void build() {
        System.out.println("Build ChineseTutor");
    }
}
public class MathTutor implements ITutor {
    @Override
    public void build() {
        System.out.println("Build MathTutor");
    }
}

# 抽象工厂(多个工厂,所以抽象出一个接口约定行为)
public interface IGroup {
    ITutor createTutor();
    ITeacher createTeacher();
}
public class ChineseIGroup implements IGroup {
    @Override
    public ITutor createTutor() {
        ChineseTutor chineseTutor = new ChineseTutor();
        chineseTutor.build();
        return chineseTutor;
    }
    @Override
    public ITeacher createTeacher() {
        ChineseTeacher chineseTeacher = new ChineseTeacher();
        chineseTeacher.build();
        return chineseTeacher;
    }
}
public class MathIGroup implements IGroup {
    @Override
    public ITutor createTutor() {
        MathTutor mathTutor = new MathTutor();
        mathTutor.build();
        return mathTutor;
    }
    @Override
    public ITeacher createTeacher() {
        MathTeacher mathTeacher = new MathTeacher();
        mathTeacher.build();
        return mathTeacher;
    }
}

# 使用
IGroup chineseGroup = new ChineseIGroup();
ChineseTeacher chineseTeacher = (ChineseTeacher) chineseGroup.createTeacher();
System.out.println(chineseTeacher.getClass());
ChineseTutor chineseTutor = (ChineseTutor) chineseGroup.createTutor();
System.out.println(chineseTutor.getClass());

IGroup mathGroup = new MathIGroup();
MathTeacher mathTeacher = (MathTeacher) mathGroup.createTeacher();
System.out.println(mathTeacher.getClass());
MathTutor mathTutor = (MathTutor) mathGroup.createTutor();
System.out.println(mathTutor.getClass());

在这里插入图片描述

我们在创建时指定了具体的工厂类后,在使用时就无需再关心是哪个工厂类

抽象工厂模式很好的发挥了开闭原则依赖倒置原则,但缺点是 抽象工厂模式太重了,如果 IFactory 接口需要新增功能,则会影响到所有的具体工厂类。使用抽象工厂模式,替换具体工厂时只需更改一行代码,但要新增抽象方法则需要修改所有的具体工厂类。所以抽象工厂模式适用于增加同类工厂这样的横向扩展需求,不适合新增功能这样的纵向扩展

抽象工厂在实际中的使用例子

抽象工厂模式 主要 用于替换一系列方法
例如将程序中的 SQL Server 数据库整个替换为 Access 数据库,使用抽象方法模式的话,只需在 IFactory 接口中定义好增删改查四个方法,让 SQLFactory 和 AccessFactory 实现此接口,调用时直接使用 IFactory 中的抽象方法即可,调用者无需知道使用的什么数据库,我们就可以非常方便的整个替换程序的数据库,并且让客户端毫不知情。

在这里插入图片描述

[Q&A] 工厂方法模式 和 抽象工厂模式的区别

工厂方法关注单个产品等级结构(Product Hierarchy)的实例化,强调的是单一对象的创建过程。

抽象工厂则关注多个产品族(Product Family)的实例化,强调的是多个相互关联的产品对象的协调创建过程。

在实际运用中,如果需求是创建某一类对象,并且这个对象类型可能会扩展,则适合使用工厂方法模式;
如果需要创建一系列相关的对象,而这些对象间又具有某种一致性约束或联系,那么抽象工厂模式更为合适。

在这里插入图片描述

参考

如何用「设计模式」制作珍珠奶茶?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值