设计模式之工厂奇旅:解锁高效编程新境界,让你的代码焕发活力!

目录

工厂模式

1. 音乐推荐器1.0版本

2. 音乐推荐器2.0版本

3. 音乐推荐器3.0版本


工厂模式

工厂模式是平时开发过程中最常见的设计模式。工厂模式解决类的实例化问题,它属于创建型模式。工厂模式也经常会和其他设计模式组合使用。

试想你去麦当劳买一个汉堡,你只需要告诉收银员要一个xx汉堡。过一会就会有一个此类型的汉堡被制作出来。而你完全不需要知道这个汉堡是怎么被制作出来的。这个例子中你就是客户端代码,麦当劳就是工厂,负责生产汉堡。汉堡是接口,而具体的某一种汉堡,比如说香辣鸡腿堡,就是实现了汉堡接口的类。

我们继续通过另外一个例子,深入理解工厂模式。现在我们给某款音乐软件开发一个推荐功能。需求是能够根据用户选择的音乐风格,推荐不同风格的歌曲清单,那么你打算怎么实现呢?


1. 音乐推荐器1.0版本

 如果之前没有学习过设计模式,很可能你的实现会是这样。编写RecommendMusicService 类,里面有一个Recommend方法。根据输入的风格不同,执行不同的推荐逻辑。代码如下:

public class RecommendMusicService {
    public List<String> recommend(String style) {
        List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {
            recommendMusicList.add("Don't cry");
        } else if ("country".equals(style)) {
            recommendMusicList.add("Hotel california");
        } else if ("grunge".equals(style)) {
            recommendMusicList.add("About a girl");
        }else {
            recommendMusicList.add("My heart will go on");
        }

        return recommendMusicList;
    }
}

是不是觉得recommed方法太长了?OK,我们重构下,把每种音乐风格的推荐逻辑封装到相应的方法中,这样推荐方法就可以复用了。

public class RecommendMusicService {
    public List<String> recommend(String style) {
        List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {
            recommendMetal(recommendMusicList);
        } else if ("country".equals(style)) {
            recommendCountry(recommendMusicList);
        } else if ("grunge".equals(style)) {
            recommendGrunge(recommendMusicList);
        }else {
            recommendPop(recommendMusicList);
        }

        return recommendMusicList;
    }

    private void recommendPop(List<String> recommendMusicList) {
        recommendMusicList.add("My heart will go on");
        recommendMusicList.add("Beat it");
    }

    private void recommendGrunge(List<String> recommendMusicList) {
        recommendMusicList.add("About a girl");
        recommendMusicList.add("Smells like teen spirit");
    }

    private void recommendCountry(List<String> recommendMusicList) {
        recommendMusicList.add("Hotel california");
        recommendMusicList.add("Take Me Home Country Roads");
    }

    private void recommendMetal(List<String> recommendMusicList) {
        recommendMusicList.add("Don't cry");
        recommendMusicList.add("Fade to black");
    }
}

这样是不是很完美了!recommend方法精简了很多,而且每种不同的推荐逻辑都封装到相应的方法中了,那么,如果再加一种风格推荐怎么办?这有什么难,recommend方法中加分支就好啦。然后在RecommendMusicService中增加一个对应的推荐方法。

等等,是不是哪里不太对?回想一下设计模式6大原则的开闭原则----对扩展开放,对修改关闭。面对新风格推荐的需求,我们一直都在修改RecommendMusicService这个类。以后每次有新风格推荐要添加,都会导致修改 RecommendMusicService 。显然这是个坏味道。

那么如何做到实现新的风格推荐需求时,满足开闭原则呢?


2. 音乐推荐器2.0版本

添加新需求时,如何做到不修改,去扩展?是不是想到了单一职责?是的,类的职责越单一,那么它就越稳定。RecommendMusicService类的职责太多了,负责n种风格的推荐。OK,那么我们第一件事就是要减少RecommendMusicService类的职责,把每种不同风格的推荐提取到不同的类当中。
比如MetalMusicRecommendServicePopMusicRecommendServiceCountryMusicRecommendService。这些类都可以通过recommed方法生成推荐的歌曲清单。而RecommendMusicService类只是通过调用不同MusicRecommendService的recommed方法来实现推荐。代码如下:

MetalMusicRecommendService类:

public class MetalMusicRecommendService {
    public List<String> recommend(){
        List<String> recommendMusicList = new ArrayList<>();

        recommendMusicList.add("Don't cry");
        recommendMusicList.add("Fade to black");

        return recommendMusicList;
    }
}

同类型的还有GrungeMusicRecommendServicePopMusicRecommendServiceCountryMusicRecommendService

现在我们来改造MusicRecommendService类:

public class RecommendMusicService {

    private MetalMusicRecommendService metalMusicRecommendService = new MetalMusicRecommendService();
    private GrungeMusicRecommendService grungeMusicRecommendService = new GrungeMusicRecommendService();
    private CountryMusicRecommendService countryMusicRecommendService = new CountryMusicRecommendService();
    private PopMusicRecommendService popMusicRecommendService = new PopMusicRecommendService();

    public List<String> recommend(String style) {
        List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {
            metalMusicRecommendService.recommend();
        } else if ("country".equals(style)) {
            countryMusicRecommendService.recommend();
        } else if ("grunge".equals(style)) {
            grungeMusicRecommendService.recommend();
        }else {
            popMusicRecommendService.recommend();
        }

        return recommendMusicList;
    }

}

改造后,如果有了新音乐风格推荐的需求,只需要增加相应的xxxMusicRecommendService类。然后在RecommendMusicService中增加相应分支即可。这样就做到了开闭原则。那么还有什么违背设计原则的地方吗?RecommendMusicService是不是依赖的xxMusicRecommendService类太多了?

没错,而且这么多类,实际上都是做推荐的事情,且都是通过recommend方法提供推荐结果。这完全可以抽象出接口,比如MusicRecommendInterface。那么RecommendMusicService依赖MusicRecommendInterface就可以了。这解决了依赖反转问题----应该依赖接口,而不是依赖具体实现。

我们又复习了单一职责和依赖反转原则。不愧是指导设计模式的原则,真的是无处不在。依赖MusicRecommendInterface没问题,但是不同的音乐风格,怎么能实例化MusicRecommendInterface的某个具体实现呢?工厂模式于是就应运而生了!


3. 音乐推荐器3.0版本

我们回顾一下文章开头说到,工厂模式解决的是类的实例化。无论你需要哪种风格的MusicRecommendService,只需要告诉工厂,工厂会给你实例化好你需要的具体实现。而工厂能做到这些是基于继承和多态。
RecommendMusicService只需要依赖MusicRecommendInterface,具体需要哪个MusicRecommendService的实现,只需要告诉RecommendServiceFactory即可。MusicRecommendService拿到具体的实现后调用它的recommand方法,就可以得到相应风格的推荐歌曲清单。

首先我们需要定义所有MusicRecommendService要实现的接口,很简单,只有一个recommend方法:

public interface MusicRecommendInterface {
    List<String> recommend();
}

我们2.0版本中的xxxMusicRecommendService都需要实现此接口,例如:

public class GrungeMusicRecommendService implements MusicRecommendInterface {
    public List<String> recommend() {
        List<String> recommendMusicList = new ArrayList<>();

        recommendMusicList.add("About a girl");
        recommendMusicList.add("Smells like teen spirit");

        return recommendMusicList;
    }
}

不同音乐风格的推荐逻辑在各自实现的recommend()方法中。
下面就是工厂模式中的工厂代码了,其实很简单,只是根据不同的参数实例化不同的实现并返回。

public class MusicRecommendServiceFactory {
    MusicRecommendInterface createMusicRecommend(String style) {
        if ("metal".equals(style)) {
            return new MetalMusicRecommendService();
        } else if ("country".equals(style)) {
            return new CountryMusicRecommendService();
        } else if ("grunge".equals(style)) {
            return new GrungeMusicRecommendService();
        } else {
            return new PopMusicRecommendService();
        }
    }
}

我们再来看看RecommendMusicService的代码:

public class RecommendMusicService {

    private MusicRecommendServiceFactory recommendMusicServiceFactory = new MusicRecommendServiceFactory();

    public List<String> recommend(String style) {

        MusicRecommendInterface musicRecommend = recommendMusicServiceFactory.createMusicRecommend(style);

        return musicRecommend.recommend();
    }
}

是不是简单多了,已经不再依赖那么多的MusicRecommendInterface的实现了。它要做的事情仅仅是通过工厂得到想要的RecommendMusicService实现,然后调用它的recommend()方法,就可以得到你想要的推荐结果。
类图如下:

以上三种实现方式总结如下:

  • 31
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

建爱永恒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值