预计阅读时间:10-14min
情景引入:
「得不到的永远在骚动,买不起的都是在装聋」
(某商场)
子乾:诶诶诶,这儿有一个 HW 体验店,你确定不进去看看嘛?
朱少:走走瞧瞧看,手机差不多换它一个。
子乾:你看这个,这个音响,我喜欢。
朱少:喜欢有屁用,有钱买吗?我有一个小M的,用着挺好。
子乾:我不,我偏买。我还要手机,俩品牌的都要。
朱少:到家再买。哥写代码挣钱再给你买。
(快用代码实现一下)
回顾工厂模式:
在工厂模式中,每一个工厂负责生产对应的一款具体的产品,具有唯一性。但有时候,人们还需要一个工厂能够提供多个产品对象。
比如上述情景,一个 HW 工厂可以提供手机和音响两个产品,而 XM 工厂也可以提供手机和音响两个产品。
当客户需要购买时,用代码模拟购买过程。
知识快充:
概念1:
产品等级结构:即产品的继承结构。比如一个抽象类(或接口)是手机,其有子类 HW手机、XM 手机。
概念2:
产品族:在抽象工厂模式中,产品族指由同一个工厂生产的位于不同产品等级结构的一组产品。比如 HW 生产的手机和音响。H 手机属于手机产品等级结构,H 音响属于手机产品等级结构。
上述情景引入中,要购买的不是一个产品,就要求工厂生产的具体产品不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品。
应使用 抽象工厂模式。
Abstrict Factory Pattern:
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
不太明白看下面:
提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。
抽象工厂模式是对象创建型模式,是所有形式的工厂模式中最为抽象和最具一般性的一种形式。
也可以这么理解,具体工厂负责创建一族产品。当某工厂可以生产出不同产品等级的一个产品族中的所有对象时,该模式更高效。
角色:
Factory :抽象工厂
ConcreteFactory :具体工厂
Product :产品
ConcreteProduct :具体产品
类图:
上述类图映射到代码中:
产品:抽象产品 具体产品的代码示例
代码语言:javascript复制// 抽象产品A
public interface AbstractProductA{
public void methodA();
}
// 具体产品A1
public class ConcreteProductA1 implememts AbstractProductA{
public void methodA(){
// To do ...
}
}
// 抽象产品B
public interface AbstractProductB{
public void methodB();
}
// 具体产品B1
public class ConcreteProductB1 implememts AbstractProductB{
public void methodB(){
// To do ...
}
}
工厂:抽象工厂 具体工厂
代码语言:javascript复制// 抽象工厂
public interface Factory{
public AbstractProductA createProductA();
public AbstractProductB createProductB();
}
// 1 号具体工厂
public class ConcreteFactory1 implements Factory{
public AbstractProductA createProductA(){
return new ConcreteProductA1();
}
public AbstractProductB createProductB(){
return new ConcreteProductB1();
}
}
客户端代码:
代码语言:javascript复制···
Factory factory;
AbstractProductA productA;
AbstractProductB productB;
factory = new ConcreteFactory1(); //实例 1 厂
productA = factory.createProductA(); // 1 厂生产 A 产品
productA.algorithmA();
productB = factoru.createProductB(); // 1 厂生产 B 产品
productB.algorithm();
回归到本例代码的解析,两个厂家,都可以生产手机和音响。
类图:
首先抽象出两个产品,一个手机,一个音响;
然后画出他们具体的子类。
其次抽象出一个工厂,工厂可以生产两种产品,手机和音响;
然后有两个具体工厂,每一个工厂都可以生产这两种产品,手机和音响;
工厂和产品具有“生产、创建”的关系,具体产品依赖具体工厂。
最后,在客户端使用抽象类存储具体的对象,完美的里氏代换原则。
代码:
第一步:定义抽象产品,手机接口:
代码语言:javascript复制package com.sample.abstractfactorypattern.product;
public interface Phone {
public void call();
}
第二步:实现该接口,HWPhone 和 XMPhone:
代码语言:javascript复制// HWPhone
package com.sample.abstractfactorypattern.product;
public class HWPhone implements Phone {
@Override
public void call() {
System.out.println("正在使用 HWPhone ...");
}
}
// XMPhone
package com.sample.abstractfactorypattern.product;
public class XMPhone implements Phone{
@Override
public void call() {
System.out.println("正在使用 XMPhone 。。。");
}
}
第三步:定义音响产品接口
代码语言:javascript复制package com.sample.abstractfactorypattern.product;
public interface Sound {
public void play();
}
第四步:实现音响接口,定义 HWSound 类和 XMSound 类:
代码语言:javascript复制// HWSound
package com.sample.abstractfactorypattern.product;
public class HWSound implements Sound {
@Override
public void play() {
System.out.println("已购买 HWSound 。。。");
}
}
// XMSound
package com.sample.abstractfactorypattern.product;
public class XMSound implements Sound{
@Override
public void play() {
System.out.println("已购买 XMSound... ");
}
}
第五步:定义抽象工厂,它包含两个方法,因为有两个产品:
代码语言:javascript复制package com.sample.abstractfactorypattern.factory;
import com.sample.abstractfactorypattern.product.Phone;
import com.sample.abstractfactorypattern.product.Sound;
public interface Factory {
public Phone createPhone();
public Sound createSound();
}
第六步:实现抽象工厂,定义 HWFactory 和 XMFactory,此时返回的即产品对象,可表示 产品对象 被创建成功。
代码语言:javascript复制// HW 工厂
package com.sample.abstractfactorypattern.factory;
import com.sample.abstractfactorypattern.product.HWPhone;
import com.sample.abstractfactorypattern.product.HWSound;
import com.sample.abstractfactorypattern.product.Phone;
import com.sample.abstractfactorypattern.product.Sound;
public class HWFactory implements Factory {
@Override
public Phone createPhone() {
return new HWPhone();
}
@Override
public Sound createSound() {
return new HWSound();
}
}
// XM 工厂
package com.sample.abstractfactorypattern.factory;
import com.sample.abstractfactorypattern.product.Phone;
import com.sample.abstractfactorypattern.product.Sound;
import com.sample.abstractfactorypattern.product.XMPhone;
import com.sample.abstractfactorypattern.product.XMSound;
public class XMFactory implements Factory {
@Override
public Phone createPhone() {
return new XMPhone();
}
@Override
public Sound createSound() {
return new XMSound();
}
}
第七步:客户端调用实现
对象都存储在接口类型中,在下面动态进行赋值调用。
当在选定一个工厂时,就代表选择了该品牌产品;当选定哪一个工厂方法时,就代表选择了该方法下的具体产品。
省去了传入一个参数的烦扰,也可以防止参数输入错误,导致拿不到产品。
代码语言:javascript复制package com.sample.abstractfactorypattern;
import com.sample.abstractfactorypattern.factory.Factory;
import com.sample.abstractfactorypattern.factory.HWFactory;
import com.sample.abstractfactorypattern.factory.XMFactory;
import com.sample.abstractfactorypattern.product.Phone;
import com.sample.abstractfactorypattern.product.Sound;
public class Client {
public static void main(String[] args){
Factory factory;
Phone phone;
Sound sound;
// 购买 HW 手机
factory = new HWFactory();
phone = factory.createPhone();
phone.call();
// 购买 XM 音响
factory = new XMFactory();
sound = factory.createSound();
sound.play();
// 购买 XM 手机
phone = factory.createPhone();
phone.call();
// 购买 HW 音响
factory = new HWFactory();
sound = factory.createSound();
sound.play();
}
}
运行效果:
项目结构:
抽象工厂模式优点:
·隔离了具体类的生成
·当一个产品族的多个对象产品被设计成一起工作时,能保证客户端只使用同一个产品族中的对象。
·增加新的产品族比较方便,符合开闭原则。
抽象工厂模式缺点:
·增加新的产品等级结构比较麻烦,需要修改具体工厂、抽象工厂等,违背了开闭原则。
上述的优缺点也体现了抽象工厂模式下开闭原则的倾斜性:
增加新的产品族,符合开闭原则。比如,新增 PG 的手机和音响,那么只需在抽象产品接口下新增两个具体实现类,PGPhone 和 PGSound;同时,在新增一个具体工厂 PGFactory,实现抽象工厂。
而当新增产品等级结构时,不符合开闭原则。比如 HW 和 XM 两家工厂新增产品电脑。就需要新增一个抽象接口类 Computer,以及具体实现类;同时,工厂中,也需要对抽象工厂和具体工厂进行修改,增加 createComputer 方法。
模式的适用环境:
✓ 一个系统不依赖于产品类实例如何被创建、组合和表达的细节
✓ 系统中有多于一个的产品族,但每次只使用其中某一产品族
✓ 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来
✓ 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构
好了,我的读者朋友们,今天对于抽象工厂模式的分解与分享就到此结束了。对于我文中列举的例子,我说明白了吗?您感觉怎么样?欢迎与我私下交流。
感谢阅读,感谢陪伴。
表情包来源网络,侵删。
原创不易