注意:设计模式一般都输混用的
简单工厂模式
指由一个工厂对象决定创建出哪一种产品类的实例, 但它不属于 GOF 23 种设计模式。简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要 传入工厂类的参数,对于如何创建对象的逻辑不需要关心。
Demo
以支付为例,当然这里的场景不够完美,真实的支付很复杂,平台上有各种支付,比如支付宝支付,微信支付,银联支付
// 抽象的支付方式
public interface PayMethod {
// 直接调用支付
public void playPay();
}
// 这里的抽象类是为了定义一些抽象方法和模板
public abstract class AbstractPayMethod implements PayMethod {
// 1. 验证订单
public abstract void validationOrder();
// 2. 验证账户余额
public abstract void validationAccount();
// 3.支付
public abstract void pay();
// 4.通知
public abstract void notice();
public void playPay() {
validationOrder();
validationAccount();
pay();
notice();
}
}
//支付宝支付
public class AliPay extends AbstractPayMethod {
@Override
public void validationOrder() {
System.out.println("支付宝支付验证订单");
}
@Override
public void validationAccount() {
System.out.println("支付宝验证账户");
}
@Override
public void pay() {
System.out.println("支付宝支付");
}
@Override
public void notice() {
System.out.println("通知");
}
}
// 微信支付
public class WeChatPay extends AbstractPayMethod {
@Override
public void validationOrder() {
}
@Override
public void validationAccount() {
}
@Override
public void pay() {
}
@Override
public void notice() {
}
}
// 工厂类
public class PayFactory {
private PayFactory(){}
private final static Map<Class<? extends PayMethod>,PayMethod> payMap = new HashMap<>();
// 如果我想修改或者新增支付方式要修改这个工厂类 不满足开闭原则
static {
payMap.put(AliPay.class,new AliPay());
payMap.put(WeChatPay.class,new WeChatPay());
// 银联支付 自己写
payMap.put(UnionPay.class,new UnionPay());
// 跨境支付
payMap.put(CrossBorderPay.class,new CrossBorderPay());
}
public static PayMethod createPayMethod(Class<? extends PayMethod> clazz) {
return payMap.get(clazz);
}
}
//测试类
public class MainTest {
public static void main(String[] args) {
PayMethod payMethod = PayFactory.createPayMethod(AliPay.class);
payMethod.playPay();
}
}
工厂类只负责生成对象,此模式不符合开闭原则,如果要想新加产品,要修改工厂类,此模式只能符合生成小部分对象,如果太多了,就成了万能工厂,不好维 护。
JDK中的运用
Calendar这个类的getInstance方法.
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 no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
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;
}
工厂方法模式
是指定义一个创建对象的接口,但让实现这个接口的类 来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所 需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。
工厂方法模式主要解决产品扩展的问题,在简单工厂中,随着产品链的丰富,如果每个对象的创建 逻辑有区别的话,工厂的职责会变得越来越多,有点像万能工厂,并不便于维护。根据单一职责原则我 们将职能继续拆分,专人干专事。
Demo
// 支付方式的抽象
public interface PayMethodInterface {
// 调用支付
public void playPay();
}
public abstract class AbstractPayMethod implements PayMethodInterface{
// 1. 下单请求
public abstract void placeOrder();
// 2.支付
public abstract void pay();
// 3.通知
public abstract void notice();
public void playPay() {
placeOrder();
pay();
notice();
}
}
// 抽象的工厂
public abstract class PayFactory {
public abstract PayMethodInterface createPayMethod();
}
// 支付宝
public class AliPay extends AbstractPayMethod {
@Override
public void placeOrder() {
System.out.println("支付宝下单请求");
}
@Override
public void pay() {
System.out.println("支付宝支付");
}
@Override
public void notice() {
System.out.println("支付宝通知");
}
}
//微信
public class WeChatPay extends AbstractPayMethod {
@Override
public void placeOrder() {
System.out.println("微信支付下单请求");
}
@Override
public void pay() {
System.out.println("微信支付");
}
@Override
public void notice() {
System.out.println("通知");
}
}
// 阿里的工厂
public class AliPayFactory extends PayFactory {
@Override
public PayMethodInterface createPayMethod() {
return new AliPay();
}
}
// 微信的工厂
public class WeChatPayFactory extends PayFactory{
@Override
public PayMethodInterface createPayMethod() {
return new WeChatPay();
}
}
// 测试类
public class MainTest {
public static void main(String[] args) {
PayFactory payFactory = new AliPayFactory();
PayMethodInterface payMethod = payFactory.createPayMethod();
payMethod.playPay();
}
}
JDK中的运用

工厂方法适用于以下场景:
1、创建对象需要大量重复的代码。
2、客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
3、一个类通过其子类来指定创建哪个对象。
工厂方法也有缺点:
1、类的个数容易过多,增加复杂度。
2、增加了系统的抽象性和理解难度。
抽象工厂模式
指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一 系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类 的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

从上图中看出有正方形,圆形和菱形三种图形,相同颜色深浅的就代表同一个产品族,相同形状的代表 同一个产品等级结构。同样可以从生活中来举例,比如,美的电器生产多种家用电器。那么上图中,颜 色最深的正方形就代表美的洗衣机、颜色最深的圆形代表美的空调、颜色最深的菱形代表美的热水器, 颜色最深的一排都属于美的品牌,都是美的电器这个产品族。再看最右侧的菱形,颜色最深的我们指定 了代表美的热水器,那么第二排颜色稍微浅一点的菱形,代表海信的热水器。同理,同一产品结构下还 有格力热水器,格力空调,格力洗衣机。
Demo
// 支付方式抽象
public interface PayMethodInterface {
// 支付
public IPay playPay();
// 结算
// 退款
public IRefund refund();
//订单状态查询
// 支付方式(快捷支付,协议支付)
//跨境支付(支持货币,汇率换算)
}
// 支付
public interface IPay {
// 1. 下单请求
public abstract void placeOrder();
// 2.支付
public abstract void pay();
// 3.通知
public abstract void notice();
}
//退款
public interface IRefund {
// 发起退款请求
public void refund();
// 验证订单
public void validationOrder();
}
// 支付宝支付
public class AliPay implements IPay {
@Override
public void placeOrder() {
System.out.println("支付宝支付下单请求");
}
@Override
public void pay() {
System.out.println("支付宝支付");
}
@Override
public void notice() {
System.out.println("支付宝支付通知");
}
}
// 支付宝退款
public class AliRefund implements IRefund {
@Override
public void refund() {
System.out.println("支付宝退款请求");
}
@Override
public void validationOrder() {
System.out.println("支付宝验证订单");
}
}
// 支付宝的工厂
public class AliPayFactory implements PayMethodInterface {
@Override
public IPay playPay() {
return new AliPay();
}
@Override
public IRefund refund() {
return new AliRefund();
}
}
// 微信支付
public class WeChatPay implements IPay {
@Override
public void placeOrder() {
System.out.println("微信下单请求");
}
@Override
public void pay() {
System.out.println("微信支付");
}
@Override
public void notice() {
System.out.println("微信通知");
}
}
// 微信退款
public class WeChatRefund implements IRefund {
@Override
public void refund() {
System.out.println("微信退款请求");
}
@Override
public void validationOrder() {
System.out.println("微信验证订单");
}
}
// 微信工厂
public class WeChatFactory implements PayMethodInterface {
@Override
public IPay playPay() {
return new WeChatPay();
}
@Override
public IRefund refund() {
return new WeChatRefund();
}
}
其实这个也是不符合开闭原则的,因为增加产品会修改抽象工厂,然后每个子类的都需要去修改。