博客
关于我
设计模式一(工厂模式)
阅读量:241 次
发布时间:2019-03-01

本文共 7535 字,大约阅读时间需要 25 分钟。

不用设计模式并非不可以,但是用好设计模式能帮助我们更好的解决实际问题,设计模式最重要的是解耦。设计模式天天都在用,但自己确无从感知。最近学习了设计模式,做此笔记进行记录方便日后查阅,也分享给有需要的小伙伴!

经典框架都在用设计模式解决问题

简单列举 Spring 框架中使用到的经典设计模式:

设计模式名称 举例
工厂模式 BeanFactory
装饰器模式 BeanWrapper
代理模式 AopProxy
策略模式 HandlerMapping
模板模式 JdbcTemplate
适配器模式 HandlerAdapter
委派模式 DispatchServlet
观察者模式 ContextLoaderListener

需要注意的是,设计模式从来都不是单个独立使用的。实际应用场景中,都是多个设计模式混合使用,你中有我,我中有你。本次学习顺序为:

类型 名称 英文
创建型模式 工厂模式 Factory Pattern
单例模式 Singleton Pattern
原型模式 Prototype Pattern
结构型模式 适配器模式 Adapter Pattern
装饰器模式 Decorator Pattern
代理模式 Proxy Pattern
行为型模式 策略模式 Strategy Pattern
模板模式 Template Pattern
委派模式 Delegate Pattern
观察者模式 Observer Pattern

工厂模式详解

简单工厂模式

简单工厂模式(Simple Factory Pattern)是由一个工厂对象创建出哪一种产品类的实例,但他不属于GOF23 种设计模式。简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑并不关心。

来看一个简单 demo,程序员需要学习很多门技术,比如学习 Java、Spring等等一系列我们先来创建一个接口:

public interface ICourse {    /**     * 课程学习     * @return     */    void study();}

然后创建对应的课程:

public class JavaCourse implements ICourse {    public void study() {        System.out.println("学习Java课程");    }}public class SpringCourse implements ICourse {    public void study() {        System.out.println("学习 Spring 课程");    }}

再来创建我们的工厂方法:

public class CourseFactory {    public ICourse create(Class
clazz){ try { if (null != clazz) { return clazz.newInstance(); } }catch (Exception e){ e.printStackTrace(); } return null; }}

下面进行简单工厂方法的实际应用测试:

public class SimpleFactoryTest {    public static void main(String[] args) {        CourseFactory factory = new CourseFactory();		ICourse course = factory.create(JavaCourse.class);		course.study();    }}

这里使用到了类的反射来动态创建需要学习的课程,原因很简单,如果后面再新增了其他的学习课程,就不需要再去修改工厂方法的代码,一劳永逸了。

简单工厂在 JDK 源码中也是无处不在,例如Calendar类:

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;    }

简单工厂也有他的缺点:工厂类的职责相对过重,不易于扩展过于复杂的的产品结构。

 

工厂方法模式

工厂方法模式(Factory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。

工厂方法模式主要解决产品扩展的问题,在简单工厂中,随着产品链的丰富,如果每个课程的创建逻辑有区别的话,工厂的职责会变的越来越多,有点像万能工厂,并不便于维护。根据单一职责,我们将职责继续拆分,专人干专事。Java 课程由Java 工厂创建,Spring 课程由 Spring 工厂创建,对工厂本身也做一个抽象。

和简单工厂一样,我们先来创建基本的课程接口及其实现类:

public interface ICourse {    /**     * 学习课程     * @return     */    void study();}public class JavaCourse implements ICourse {    public void study() {        System.out.println("学习Java课程");    }}public class SpringCourse implements ICourse {    public void study() {        System.out.println("学习 Spring 课程");    }}

接着,我们来创建对应的工厂方法类:

public interface ICourseFactory {    ICourse create();}public class JavaCourseFactory implements ICourseFactory {    public ICourse create() {        return new JavaCourse();    }}public class SpringCourseFactory implements ICourseFactory {    public ICourse create() {        return new SpringCourse();    }}

可以看出,现在已经是专人干专事了,谁的工厂就只负责谁的业务。下面我们开始进行测试:

public class FactoryMethodTest {    public static void main(String[] args) {        ICourseFactory factory = new SpringCourseFactory();        ICourse course = factory.create();        course.study();        factory = new JavaCourseFactory();        course = factory.create();        course.study();    }}

通过类图来看一下他们直接的关系:

工厂方法在实际应用中,也有很多地方用到,比如 logback就用到了:

工厂方法适用于一下场景:

  1. 创建对象需要大量重复的代码;
  2. 应用层不依赖于产品类实例如何被创建、实现等细节;
  3. 一个类通过其子类来指定创建哪个对象;

工厂方法也有其缺点:

  1. 类的个数容易过多,增加复杂度;
  2. 增加了系统的抽象性和理解难度;

抽象工厂模式

抽象工厂模式(Abastract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。客户端不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以相同的接口出现,从而使客户端不依赖于具体实现。

首先定义笔记接口:

/***  定义笔记接口*/public interface INote {    void edit();}

定义学习视频接口: 

public interface IVideo {    void study();}

定义抽象工厂:

/** * 抽象工厂是用户的主入口 * 在Spring中应用得最为广泛的一种设计模式 * 易于扩展 */public abstract class CourseFactory {    public void init(){        System.out.println("初始化基础数据");    }    protected abstract INote createNote();    protected abstract IVideo learnVideo();}

接下来创建 Java 产品族,Java 学习笔记类:

public class JavaNote implements INote {    public void edit() {        System.out.println("编写Java笔记");    }}

 扩展 Java 产品等级,Java 学习视频类:

public class JavaVideo implements IVideo {	public void study() {        System.out.println("学习Java视频");    }}

创建 Java 产品族的具体工厂类: 

public class JavaCourseFactory extends CourseFactory {    @Override	public INote createNote() {        super.init();        return new JavaNote();    }    @Override	public IVideo learnVideo() {        super.init();        return new JavaVideo();    }}

 然后创建 Spring 产品族,Spring 笔记类:

public class SpringNote implements INote {    public void edit() {        System.out.println("记录Spring笔记");    }}
public class SpringVideo implements IVideo {    public void study() {        System.out.println("学习 spring 视频");    }}

 创建 spring 产品的具体工厂:

public class SpringCourseFactory extends CourseFactory {    @Override	public INote createNote() {        super.init();        return new SpringNote();    }    @Override	public IVideo learnVideo() {        super.init();        return new SpringVideo();    }}

下面来进行测试:

public class AbstractFactoryTest {    public static void main(String[] args) {        JavaCourseFactory javaCourseFactory = new JavaCourseFactory();		javaCourseFactory.createNote().edit();		javaCourseFactory.learnVideo().study();		SpringCourseFactory springCourseFactory = new SpringCourseFactory();		springCourseFactory.learnVideo().study();		springCourseFactory.createNote().edit();    }}

通过上面的代码,可以看出,抽象工厂完美的描述了两个产品族,很清晰的描述了这样一层复杂的关系。但是,如果我们继续扩展,将我们的学习源码也加入其中,就需要调整抽象工厂和具体工厂,不符合开闭原则。因此抽象工厂也有缺点:

  1. 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的方法;
  2. 增加的系统的抽象性和理解难度;

在实际工作中,产品升级迭代是很正常的事,只要不是经常性的修改,还是可以不遵循开闭原则的。

 

 

下一篇:

转载地址:http://rahx.baihongyu.com/

你可能感兴趣的文章
QT动画框架:属性动画
查看>>
泛型算法:查找初始最长有序子序列算法is_sorted_until()
查看>>
泛型算法:部分排序算法partial_sort()、partial_sort_copy()
查看>>
泛型算法:不完全排序nth_element()
查看>>
windowsC盘msp文件清理
查看>>
进程切换与线程切换的区别
查看>>
Linux部署sendmail邮件服务器
查看>>
Centos7部署NFS-V4
查看>>
FASTDFS ERROR 客户端连接服务端出现了io异常
查看>>
写了一个测试的webservice项目,如何在服务器上运行jar包 JAVA项目启动脚本
查看>>
222. Count Complete Tree Nodes
查看>>
13. Roman to Integer
查看>>
“路西法”利用Windows系统漏洞攻击并进行恶意挖矿!
查看>>
数学_几何+中位数
查看>>
C语言和32位汇编语言关于if-else分支结构的对比分析
查看>>
阿里云服务器中XAMPP(Apache)无法用外网访问的原因之一
查看>>
Java小白的入门之路
查看>>
少儿编程100讲轻松学python(一)-python怎么打开
查看>>
HDU - 6071 Lazy Running 同余最短路 + 分层
查看>>
leetCode 542 01矩阵(二维dp)
查看>>