目录
- 1.前言
- 2.工厂模式
- 2.1 简单工厂方法
- 2.2 静态工厂方法
- 2.3 抽象工厂方法
- 3.策略模式
- 4.区别与联系
- 4.1定义与核心意图
- 4.2 UML 结构对比
- 4.3 关键组成对比
- 4.4 应用场景对比
1.前言
最近接手的项目真的是太无语了,经历了多数人的编写,什么牛马鬼神写法都有,大量的 if-else,一个方法几千行,维护起来特别头大,造成这种原因就是没有充分的利用设计模式,利用设计模式编写的代码,后期维护和扩展都特别容易,下面就通过几个简单案例了解下设计模式的玩法;
2.工厂模式
2.1 简单工厂方法
// 定义一个产品接口
public interface Phone {
void callPhone();
}
// 定义具体子类产品实现
public class HuaWeiPhone implements Phone{
@Override
public void callPhone() {
System.out.println("正在使用华为手机打电话");
}
}
// 定义具体子类产品实现
public class XiaoMiPhone implements Phone{
@Override
public void callPhone() {
System.out.println("正在使用小米手机打电话");
}
}
// 定义工厂,提供一个公共获取产品接口的方法
public class PhoneFactory {
public Phone fetchPhone(String certificate) {
switch (certificate) {
case "xiaomi":
return new XiaoMiPhone();
case "huawei":
return new HuaWeiPhone();
default:
System.out.println("无法解析凭证");
return null;
}
}
}
// 测试
public class SimpleTest {
public static void main(String[] args) {
// 创建工厂
PhoneFactory phoneFactory = new PhoneFactory();
// 获取具体工厂实例
Phone xiaomi = phoneFactory.fetchPhone("xiaomi");
xiaomi.callPhone(); //输出: 正在使用小米手机打电话
}
}
玩法步骤:
1.创建一个产品接口
2.创建子类去实现接口
3.创建工厂,给定一个获取实例对象的方法
优点:主业务部分不关心具体实例的创建细节,把创建的逻辑解耦出去
缺点:每次有新添加的子类,都需要改动工厂类(不管是调整工厂类为多方法,还是指定字符),违反了外开内闭的原则
2.2 静态工厂方法
对于上述工厂方法调用中,每次都需要去实例化工厂,特别麻烦,可以把工厂静态化,直接调用;
// 在工厂提供类中直接静态实例化子类工厂
public class ManyFactory {
public static Phone fetchXiaomiPhone() {
return new XiaoMiPhone();
}
public static Phone fetchHuaweiPhone() {
return new HuaWeiPhone();
}
}
// 测试
public class ManyFactoryTest {
public static void main(String[] args) {
Phone phone = ManyFactory.fetchHuaweiPhone();
phone.callPhone();// 输出:正在使用华为手机打电话
}
}
不管怎么去调整,原则上都是工厂方法,每次添加子类工厂,都需要改变工厂提供类,违反了外开内闭的原则,所以引入了抽象工厂,就可以很好的解决这个问题;
2.3 抽象工厂方法
// 定义产品接口
public interface Car {
void car();
}
// 具体子类产品实现
public class HuaweiCar implements Car{
@Override
public void car() {
System.out.println("Huawei car");
}
}
// 具体子类产品实现
public class XiaomiCar implements Car{
@Override
public void car() {
System.out.println("Xiaomi SU7 Ultra");
}
}
// 抽象工厂 ,返回产品接口
public abstract class CarFactory {
public abstract Car fetchCar();
}
// 定义子类工厂
public class HuaweiFactory extends CarFactory {
@Override
public Car fetchCar() {
return new HuaweiCar();
}
}
// 定义子类工厂
public class XiaomiFactory extends CarFactory {
@Override
public Car fetchCar() {
return new XiaomiCar();
}
}
// 测试
public class AbstractFactoryTest {
public static void main(String[] args) {
XiaomiFactory xiaomiFactory = new XiaomiFactory();
Car car = xiaomiFactory.fetchCar();
car.car();// 输出: Xiaomi SU7 Ultra
}
}
玩法:
1.创建一个产品接口
2.创建具体子类实现接口
3.创建一个抽象工厂接口,定义一个抽象方法,返回产品接口
将工厂抽象出来,由子工厂去实现创建实例,对外的扩展性好,新增产品时,只需要增加子工厂即可
3.策略模式
一个策略多种实现,把具体的实现都封装起来,提供一个策略接口,通过上下文进行封装,在外部调用即可,有新策略,添加子策略即可
// 定义策略接口
public interface IntegrationStrategy {
/**
* 获取价格
* @param price 总价
* @param num 数量
*/
double fetchPrice(double price,int num);
}
// 定义子类的策略
public class OrdinaryStrategy implements IntegrationStrategy{
@Override
public double fetchPrice(double price, int num) {
return price * num;
}
}
// 定义子类的策略
public class IntermediateStrategy implements IntegrationStrategy{
@Override
public double fetchPrice(double price, int num) {
return price * num - (price * num * 0.2);
}
}
// 定义子类的策略
public class AdvancedStrategy implements IntegrationStrategy {
@Override
public double fetchPrice(double price, int num) {
return (price * num) - (price * num * 0.4);
}
}
// 定义上下文进行封装策略接口
public class IntegrationContext {
// 定义属性:策略接口
private final IntegrationStrategy integrationStrategy;
public IntegrationContext(IntegrationStrategy integrationStrategy) {
this.integrationStrategy = integrationStrategy;
}
// 提供一个可策略接口的执行方法
public double executeIntegration(double price,int num) {
return integrationStrategy.fetchPrice(price,num);
}
}
// 这里的策略可以考虑抽成一个简单工厂的方法,方便外部调用管理
public class StrategyFactory {
public static IntegrationStrategy fetchStrategy(String sign) {
switch (sign) {
case "Ordinary" :
return new OrdinaryStrategy();
case "Advanced" :
return new AdvancedStrategy();
case "Intermediate" :
return new IntermediateStrategy();
default:
System.out.println("未支持的标识");
return null;
}
}
}
//测试
public class StrategyTest {
public static void main(String[] args) {
// 获取具体策略
IntegrationStrategy strategy = StrategyFactory.fetchStrategy("Advanced");
// 通过上下文 调用策略方法
IntegrationContext context = new IntegrationContext(strategy);
double integration = context.executeIntegration(250, 3);
System.out.println("折扣的价格是:" + integration);// 输出:450
}
}
玩法:
1.创建一个策略接口
2.创建具体子类策略实现接口
3.创建一个上下文(定义属性:策略接口,有参构造方法,提供提供一个可策略接口的执行方法)
4.区别与联系
4.1定义与核心意图
通过上述简单的案例可以了解到两者的区别与联系
模式 | 定义 | 目的 |
---|---|---|
抽象工厂模式 | 提供一个创建一系列相关或依赖对象的接口,而无需指定它们的具体类 | 解决产品族对象创建的问题,隐藏具体类 |
策略模式 | 定义一系列算法,将每个算法封装起来,并使它们可以互换 | 在运行时选择算法或行为,提高灵活性 |
4.2 UML 结构对比
抽象工厂模式 UML 简图:
AbstractFactory
/ \
ProductAFactory ProductBFactory
| |
ProductA ProductB
策略模式 UML 简图:
Context
|
Strategy(接口)
/ \
StrategyA StrategyB
4.3 关键组成对比
对比项 | 抽象工厂模式 | 策略模式 |
---|---|---|
设计意图 | 创建一系列产品对象(产品族) | 动态选择行为或算法 |
核心角色 | 抽象工厂、具体工厂、抽象产品、具体产品 | 上下文(Context)、策略接口、具体策略类 |
关注点 | 产品的创建过程 | 行为的动态切换 |
变化点 | 工厂类与产品族 | 策略行为的实现类 |
4.4 应用场景对比
场景 | 抽象工厂模式 | 策略模式 |
---|---|---|
操作系统平台相关的 GUI 工厂(Windows / Linux) | ✅ | ❌ |
算法切换:排序算法、压缩算法、支付方式等 | ❌ | ✅ |
产品对象有多个等级结构且系统需要独立于产品的创建过程 | ✅ | ❌ |
动态改变行为(如日志策略、推荐算法) | ❌ | ✅ |
虽然两种设计模式有着诸多的不同,解决的问题也不同,但它们也可以组合使用;
下一文章就结合日常支付的场景做个结合使用的案例;