02-工厂模式
02-工厂模式
1.工厂模式
- 工厂模式主要用于将对象的创建和使用分类,以及降低代码的复杂度。
- 当对象的创建过程比较复杂时,可以考虑使用工厂模式来封装对象的创建过程。
- 工厂模式模式的分类。简单工厂模式、工厂方法模式和抽象工厂模式。
2.简单工厂模式
- 简单工厂基础类。
public interface Fruit {
String name();
}
public class Apple implements Fruit {
public String name() {
return "apple";
}
}
public class Banana implements Fruit {
public String name() {
return "banana";
}
}
public class Orange implements Fruit {
public String name() {
return "Orange";
}
}
- 简单工厂模式实现方式一,每次获取对象时创建对象。
public class FruitFactory {
public static Fruit createFruit(String name) {
Fruit fruit = null;
if ("apple".equalsIgnoreCase(name)) {
fruit = new Apple();
} else if ("banana".equalsIgnoreCase(name)) {
fruit = new Banana();
} else if ("orange".equalsIgnoreCase(name)) {
fruit = new Orange();
}
return fruit;
}
}
- 简单工厂模式实现方式二,从缓存中获取对象。
public class FruitFactory {
private final static Map<String, Fruit> cacheFruit = new HashMap<>();
static {
cacheFruit.put("apple", new Apple());
cacheFruit.put("banana", new Banana());
cacheFruit.put("orange", new Orange());
}
public static Fruit createFruit(String name) {
if (name == null || name.isEmpty()) {
return null;
}
return cacheFruit.get(name.toLowerCase());
}
}
3.工厂方法模式
- 工厂方法模式基础代码。
// 具体需要创建的对象
public interface Fruit {
String name();
}
public class Apple implements Fruit {
public String name() {
return "apple";
}
}
public class Banana implements Fruit {
public String name() {
return "banana";
}
}
public class Orange implements Fruit {
public String name() {
return "Orange";
}
}
// 创建对象工厂
public interface FruitFactory {
Fruit createFruit();
}
public class AppleFruitFactory implements FruitFactory {
@Override
public Fruit createFruit() {
return new Apple();
}
}
public class BananaFruitFactory implements FruitFactory {
@Override
public Fruit createFruit() {
return new Banana();
}
}
public class OrangeFruitFactory implements FruitFactory {
@Override
public Fruit createFruit() {
return new Orange();
}
}
- 工厂方法模式调用方式一。
public class FruitSource {
public static FruitFactory createFruit(String name) {
FruitFactory fruitFactory = null;
if ("apple".equalsIgnoreCase(name)) {
fruitFactory = new AppleFruitFactory();
} else if ("banana".equalsIgnoreCase(name)) {
fruitFactory = new BananaFruitFactory();
} else if ("orange".equalsIgnoreCase(name)) {
fruitFactory = new OrangeFruitFactory();
}
return fruitFactory;
}
}
- 工厂方法模式调用方式二。
public class FruitSource {
public static FruitFactory createFruit(String name) {
FruitFactory fruitFactory = FruitFactoryMap.getFruitFactory(name);
if (fruitFactory == null) {
throw new RuntimeException("name error.");
}
return fruitFactory;
}
}
public class FruitFactoryMap {
private final static Map<String, FruitFactory> cacheFactories = new HashMap<>();
static {
cacheFactories.put("apple", new AppleFruitFactory());
cacheFactories.put("banana", new BananaFruitFactory());
cacheFactories.put("orange", new OrangeFruitFactory());
}
public static FruitFactory getFruitFactory(String name) {
if (name == null || name.isEmpty()) {
return null;
}
return cacheFactories.get(name.toLowerCase());
}
}
4.简单工厂模式和工厂方法模式的比较
-
简单工厂模式模式添加一个新Fruit时,就需要修改FruitFactory中的代码,是不是违反开闭原则呢?如果并非频繁的添加新Fruit,只是偶尔修改FruitFactory类的代码,即便FruitFactory类的实现不符合开闭元素,也是可以接受的。
-
简单工厂的第一种实现方式有较多的if...else...,是否需要替换为其他涉及模式呢?如果if...else...不多,或者if...else...更有利于代码阅读,即便代码中存储if...else...也是可以接受的。
-
简单工厂模式和工厂方法模式的使用场景。
- 工厂方法模式的实例中,每一个工厂类的功能都相当的"单薄",只包含一行代码,有点过度设计。拆分解耦的目的是降低代码的复杂度,如果代码已经足够简单,就没必要继续拆分。所以针对示例二中的逻辑可以直接使用简单工厂模式来完成。
- 如果每个对象的创建逻辑都比较复杂,如对象的创建需要组合其他类的对象,并进行复杂的初始化操作,如果我们将所有对象的创建过程放在简单工厂中,则会导致工厂类的复杂度过高。这个时候可以使用工厂方法模式将复杂的创建逻辑拆分到多个工厂类中。
5.抽象工厂模式
-
在简单工厂模式和工厂方法模式中,类只有一种分类方式。当类有两种分类模式时,通过组合可以得到6个类。甜口味的水果:SweetApple、SweetBanana和SweetOrange;酸口味的水果:SourApple、SourBanana和SourOrange。
-
针对多种分类方式的类,如果继续使用工厂方法模式实现,就会产生过多的类导致系统难以维护。针对这种特殊的场景,就可以使用抽象工厂模式,让一个工厂负责创建多种不同类型的Fruit对象。
-
抽象工厂模式部分代码。
// 两种口味的水果接口
public interface SweetFruit {
String getName();
}
public interface SourFruit {
String getName();
}
// 水果口味的具体实现类
public class SweetApple implements SweetFruit {
@Override
public String getName() {
return "sweet apple";
}
}
public class SourApple implements SourFruit {
@Override
public String getName() {
return "sour apple";
}
}
// 水果工厂
public interface FruitFactory {
SweetFruit createFruit();
SourFruit createSour();
}
public class AppleFruitFactory implements FruitFactory {
@Override
public SweetFruit createFruit() {
return new SweetApple();
}
@Override
public SourFruit createSour() {
return new SourApple();
}
}
// 省略BananaFruitFactory和OrangeFruitFactory
6.工厂模式在Java中的应用
- DateFormat的创建使用了简单工厂模式。
public class Test {
public static void main(String[] args) {
// 获取不同的DateFormat实例对象会传递不同的参数。
// 获取的对象实例都是java.text.SimpleDateFormat
DateFormat dateFormat01 = DateFormat.getInstance();
DateFormat dateFormat02 = DateFormat.getTimeInstance();
DateFormat dateFormat03 = DateFormat.getDateInstance();
DateFormat dateFormat04 = DateFormat.getDateTimeInstance();
}
}
private static DateFormat get(int timeStyle, int dateStyle,
int flags, Locale loc) {
// ... 省略其他代码
DateFormat dateFormat = get(adapter, timeStyle, dateStyle, loc);
if (dateFormat == null) {
dateFormat = get(LocaleProviderAdapter.forJRE(), timeStyle, dateStyle, loc);
}
return dateFormat;
}
// get()方法会根据不同的数据创建不同的DateFormat对象。
private static DateFormat get(LocaleProviderAdapter adapter, int timeStyle, int dateStyle, Locale loc) {
DateFormatProvider provider = adapter.getDateFormatProvider();
DateFormat dateFormat;
if (timeStyle == -1) {
dateFormat = provider.getDateInstance(dateStyle, loc);
} else {
if (dateStyle == -1) {
dateFormat = provider.getTimeInstance(timeStyle, loc);
} else {
dateFormat = provider.getDateTimeInstance(dateStyle, timeStyle, loc);
}
}
return dateFormat;
}
- Calendar的创建使用了简单工厂模式。
public class Test {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
}
}
public static Calendar getInstance()
{
Locale aLocale = Locale.getDefault(Locale.Category.FORMAT);
return createCalendar(defaultTimeZone(aLocale), aLocale);
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类