? 作者主页:欢迎来到我的技术博客😎
? 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~*
🍊 如果文章对您有帮助,记得关注、点赞、收藏、评论??????
📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉
在软件开发中,创建对象实例最常用的方式就是通过 new
操作符直接生成对象,但是有时候需要根据不同的条件来创建不同类型的对象,而直接在代码中使用 new
关键字创建对象会导致代码的耦合度增加,不利于系统的维护和扩展。在这种情况中,创建对象不仅仅只是一个 操作,而是有一个复杂的 过程。
因此,对于出现的这种的情况,我们怎么做到就是轻松方便地构造对象实例,而不用去关心对象实例的细节以及创建中的复杂流程呢?这时候我们引入 工厂类 来负责对象的创建。
在工厂模式中,通常会定义一个 抽象工厂接口,该接口声明了创建对象的方法,具体的工厂类 实现了这个接口,并负责实际 创建对象的过程。客户端代码通过使用工厂接口来创建对象,而不直接使用 new
关键字实例化对象,从而实现 对象创建和使用的解耦。
工厂模式可以分为三类:
这三种模式从上到下逐步抽象,并且更具一般性。在《设计模式》这本书中将工厂模式分为两类:工厂方法模式和抽象工厂模式,将简单工厂模式看作是工厂方法模式中的一种特例,在实际开发中,简单工厂模式反而更像是一种 编程习惯。
在引入简单工厂模式之前,我们先来演示一下没有使用工厂模式的业务场景。
在没有使用工厂模式的情况下,当客户前往手机店购买苹果手机时,手机店必须亲自进行苹果手机的制造工作;同样,如果客户想购买小米手机,手机店也必须自行进行小米手机的制造工作。
类图如下:
具体的类设计如下:
手机抽象类:
public abstract class Phone {
public abstract String getName();
//外观定制
public void addAppearance() {
System.out.println("外观定制");
}
//硬件配置
public void addConfiguration() {
System.out.println("硬件配置");
}
}
苹果手机类:
public class ApplePhone extends Phone {
@Override
public String getName() {
return "苹果手机";
}
}
小米手机类:
public class XiaomiPhone extends Phone {
@Override
public String getName() {
return "小米手机";
}
}
手机店类:
public class PhoneStore {
public Phone orderPhone(String type) {
//声明Phone类型的变量,根据不同类型创建不同的phone子类对象
Phone phone = null;
if ("Apple".equals(type)) {
phone = new ApplePhone();
} else if ("Xiaomi".equals(type)) {
phone = new XiaomiPhone();
} else {
throw new RuntimeException("暂没有该手机型号");
}
//配置
phone.addAppearance();
phone.addConfiguration();
return phone;
}
}
客户端类:
public class Client {
public static void main(String[] args) {
//1. 创建手机店类
PhoneStore store = new PhoneStore();
//2. 购买手机
Phone phone = store.orderPhone("Apple");
System.out.println(phone.getName());
}
}
至此,客户就可以在客户端中购买所需要什么品牌的手机,然后由手机店自己去制造手机后交付于客户。
说明:
在上述代码中 Phone
类被声明为抽象类,在抽象类中声明了一个抽象方法 getName()
,但是没有具体的实现方法,而具体的实现留给子类去完成。其他两个方法是具体的实现方法,子类继承直接默认获得这两个功能,不需要再去实现。
这时候我们可以发现,这不就和接口特别相似,但是两者却有着不同之处,接下来我们讲一下 抽象类 和 接口 区别:
抽象类:
接口:
public
,所有字段默认为 public, static, final
;通过上面的案例,我们看到手机店不仅要卖手机还要自己去制造手机。因此我们引入了工厂模式,我们可以使用简单工厂模式来创建一个工厂类,由工厂类去实现手机的制造,而用户只需要在客户端传入工厂类的参数,工厂类就会去制造相对应的手机出来,手机店只需去卖给客户需要的手机即可,不需要关心手机是如何被制造出来的整个过程。
简单工厂模式的核心是定义一个创建对象的接口,将对象的创建和本身的业务逻辑分离,降低系统的耦合度,当需要改变的时候,只需要修改工厂类即可。
简单工厂模式包含以下的角色:
使用简单工厂模式对上面案例进行改造,类图如下:
?
具体的类设计如下:
对于手机抽象类、苹果手机类、小米手机类、客户端这几个类我们都不需要进行修改,我们只需要修改手机店类以及创建一个工厂类即可。
工厂类:
public class SimplePhoneFactory {
public Phone createPhone(String type) {
//声明Phone类型的变量,根据不同类型创建不同的phone子类对象
Phone phone = null;
if ("Apple".equals(type)) {
phone = new ApplePhone();
} else if ("Xiaomi".equals(type)) {
phone = new XiaomiPhone();
} else {
throw new RuntimeException("暂没有该手机型号");
}
//配置
phone.addAppearance();
phone.addConfiguration();
return phone;
}
}
手机店类:
public class PhoneStore {
public Phone orderPhone(String type) {
//创建工厂类对象
SimplePhoneFactory factory = new SimplePhoneFactory();
//调用制造手机的方法
Phone phone = factory.createPhone(type);
//配置
phone.addAppearance();
phone.addConfiguration();
return phone;
}
}
优点:
简单工厂模式封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:
每次添加新产品就需要修改工厂类,不符合 “开闭原则”。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
对上面提到的 开闭原则 进行讲解,开闭原则(Open/Closed Principle,OCP)是面向对象设计中一个重要原则,它包含了两个核心概念:
针对上述简单工厂模式中的缺点,使用 工厂方法模式 就可以完美解决,完全遵循开闭原则。
工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品时,只需增加该 产品类 以及该产品对应的 具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。
工厂方法模式包含以下的角色:
使用工厂方法模式对上面案例进行改造,类图如下:
?
具体的类设计如下:
对于手机抽象类、苹果手机类、小米手机类这几个类不需要修改,而手机店类和客户端类需要修改,并且新增抽象工厂(手机工厂)、具体工厂(苹果手机工厂、小米手机工厂)。
手机工厂:
public interface PhoneFactory {
Phone createPhone();
}
苹果手机工厂:
public class ApplePhoneFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new ApplePhone();
}
}
小米手机工厂:
public class XiaomiPhoneFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new XiaomiPhone();
}
}
手机店类:
public class PhoneStore {
private PhoneFactory factory;
public void setFactory(PhoneFactory factory) {
this.factory= factory;
}
public Phone orderPhone() {
Phone phone = factory.createPhone();
//配置
phone.addAppearance();
phone.addConfiguration();
return phone;
}
}
客户端类:
public class Client {
public static void main(String[] args) {
//创建手机店对象
PhoneStore store = new PhoneStore();
//创建对象
// ApplePhoneFactory factory = new ApplePhoneFactory();
XiaomiPhoneFactory factory = new XiaomiPhoneFactory();
store.setFactory(factory);
//购买手机
Phone phone = store.orderPhone();
System.out.println(phone.getName());
}
}
优点:
缺点:
首先,我们上述案例再新增点需求,比如我们还要生产苹果手表和小米手表等产品,按照工厂方法模式的话我们需要去创建每个产品对应的产品类以及对应的具体工厂类,如果新增的产品很多的话,那么很容易发生类爆炸情况。
我们试想一下可不可以这样实现,就是属于同一品牌的产品可以由同一工厂类去创建,比如创建一个苹果工厂类,它就可以同时生产出苹果手机和苹果手表等都属于苹果品牌的产品出来。因此,我们就引入了 抽象工厂模式。
定义:抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到 同族的不同等级的产品 的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产 一个等级 的产品,而抽象工厂模式可生产 多个等级 的产品。
?
使用抽象工厂模式一般要满足以下条件:
在介绍抽象工厂模式前,我们先理解一下产品等级和产品族这两个在软件设计中经常出现的概念:
产品等级
产品族
为了方便理解,我们看一下产品等级和产品族的示意图:
抽象工厂模式包含以下的角色:
使用抽象工厂模式对上面的案例进行改造,类图如下:
?
具体的类设计如下:
对于手机抽象类、苹果手机类、小米手机类这几个类不需要修改,而客户端类、抽象工厂类需要修改,并且新增手表抽象类、苹果手表类、小米手表类、苹果工厂类、小米工厂类。
手表抽象类:
public abstract class Watch {
public abstract String getName();
}
苹果手表类:
public class AppleWatch extends Watch {
@Override
public String getName() {
return "苹果手表";
}
}
小米手表类:
public class XiaomiWatch extends Watch {
@Override
public String getName() {
return "小米手表";
}
}
抽象工厂类:
public interface PhoneAndWatchFactory {
//生产手机的功能
Phone createPhone();
//生产手表的功能
Watch createWatch();
}
苹果工厂类:
public class AppleFactory implements PhoneAndWatchFactory {
@Override
public Phone createPhone() {
return new ApplePhone();
}
@Override
public Watch createWatch() {
return new AppleWatch();
}
}
小米工厂类:
public class XiaomiFactory implements PhoneAndWatchFactory {
@Override
public Phone createPhone() {
return new XiaomiPhone();
}
@Override
public Watch createWatch() {
return new XiaomiWatch();
}
}
客户端类:
public class Client {
public static void main(String[] args) {
//创建的是苹果工厂对象
AppleFactory factory = new AppleFactory();
//获取苹果手机和苹果手表
Phone phone = factory.createPhone();
Watch watch = factory.createWatch();
System.out.println(phone.getName());
System.out.println(watch.getName());
}
}
优点:
缺点:
简单工厂模式: 让一个工厂类负责创建所有对象;但没有考虑后期扩展和维护,修改违背开闭原则,静态方法不能被继承。
工厂方法模式: 主要思想是继承,修改符合开闭原则;但每个工厂只能创建一种类型的产品。
抽象工厂模式: 主要思想是组合,本质是产品族,实际包含了很多工厂方法,修改符合开闭原则;但只适用于增加同类工厂这种横向扩展需求,不适合新增功能方法这种纵向扩展。
其实这三种工厂模式在形式和特点上都非常相似,甚至存在一定的内在联系,而且最终目的都是解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为它们之间也是可以灵活转变的。
?
非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 分享👥 留言💬thanks!!!