一文读懂如何通过设计模式学习创建对象?

创建对象最简单的方式是直接使用new操作符,但你有没有发现,我们会经常意识到这样简单粗暴的初始化会遇到代码过于“耦合”,以及有些对象实例化不应该公开地进行等问题。

小普通过示例,将介绍如何通过工厂方法模式、单例模式、建造者模式和原型模式这4种设计模式创建对象,帮助读者掌握多种创建对象的方法,从而能够设计更好的代码结构,更高效简洁地实现功能。

1.工厂方法模式

假设你要实现一个奶茶店的下单功能,作为一个菜鸟,你的代码通常都是这样写:

 例如:如果有多种类型的奶茶时,则需要增加类型判断的代码,需要根据类型去初始化对应的实例。代码示例如下:

但是,当奶茶的种类繁多,口味变化频繁时,就需要不停地去修改orderMilkTea方法,使得它能够满足我们的需求。我们可以发现,这些代码里面只有创建奶茶实例的代码会有变动,其他的代码不会发生改变。这时,你会怎么做?

一个很好的方法是:我们可以将创建奶茶实例的代码移出来进行封装,把它从orderMilkTea方法中抽离出来,创建一个新的类,只负责如何创建奶茶,这个新的类称为工厂类,它负责处理创建对象的细节。代码示例如下:

这时候,奶茶店下单的代码就依靠工厂类来创建奶茶。代码示例如下:

这种创建对象的方式我们称为简单工厂模式,某种意义上它并不算是一种设计模式,但在开发中经常被使用到。简单工厂模式通常会使用静态方法创建对象。奶茶店下单奶茶的调用关系图如下:

当奶茶的种类有变化时,就需要修改工厂类增加新的判断,去创建出新的奶茶对象,这种需要修改原有类实现的方式违反了开闭原则。通常使用反射+工厂模式来更好地实现类似的创建对象的功能,每一种具体的产品对应地创建一个工厂类,由这个具体的工厂类来创建产品,同时,客户端通过反射的方式选择要调用的工厂类去创建产品。客户端的代码示例如下:

调用关系图如下所示,

通过以上的示例,我们介绍了简单工厂模式和反射+工厂方法模式的方式创建对象,简单工厂模式和工厂方法模式非常相似,区别之处在于简单工厂模式本身包含判断创建何种对象的逻辑,而工厂方法模式需要调用者判断要实例化何种对象的工厂去创建出对应的对象。

当对象的类型有变化时,简单工厂模式需要修改工厂类,而工厂方法模式不需要,因而遵守了开闭原则。同时,简单工厂模式往往使用静态方法创建对象,无法进行继承,而工厂方法模式则相反,需要利用继承从抽象地工厂类中派生出各种具体的工厂类。

2.单例模式

假设要实现windows桌面打开一个回收站的功能,正常来说每次点击都会实例化一个回收站的实例。

实际上,多次打开回收站窗口,并没有必要实例化多个回收站的实例。因为新的实例的创建往往伴随着大量资源的消耗,给系统造成负担。如果多个窗口共享同一个实例,共享资源,那么就会给系统节省了很多资源,减少了系统资源的浪费。这个时候就需要引入单例模式,保证一个类只实例化了一个实例,并且提供了一个访问点供全局访问。

单例模式主要是通过两个步骤实现的,首先不提供公有的构造方法,使得无法在类之外实例化该类的对象实例,类的实例化完全由类内部去掌握。其次需要提供一个静态方法,外部通过调用该静态方法获得类的实例,静态方法内部设置判断是否已存在一个类的实例,不存在则创建,存在则复用不去重复创建,保证始终只实例化一个类的实例。

以上的示例在多线程的时候会存在线程安全的问题,单例模式也可以采用双重锁、静态内部类、枚举等方式去实现,可以保证线程安全,本文先不对此做展开。

3.建造者模式

假设要用程序画一个动画小人,要求很简单,只要有头、身体和四肢就行。实现的方式通常如下所示:

为了让大家更容易理解,上栗子!如果我们还要建造一个高个和矮个的小人的话,则要新建两个两个类,一个高个类和一个矮个类,去集成PersonBuilder并重写建造的方式。但是我们的客户端要去建造高个和矮个时,需要重复两次调用建造头、身体、四肢的方法。

其实对于客户端来说,建造人的过程都是一样的,没必要多次重复执行这几个方法。我们通常会引入另外一个角色,指挥者(Director),通过它控制整个的建造过程,这样客户端就不需要了解整个繁杂的建造流程,只需要告诉指挥者,我需要一个人的实例,就行了。指挥者的代码示例如下:

由于建造一个人的过程是固定的,而具体的建造细节会因高矮胖瘦而有所区别,我们将建造过程隐藏起来,客户端只需要告诉指挥者它需要的是何种类型的人即可。其建造过程的调用关系如下所示:

传统的建造者模式可以将一个产品的内部表象和产品的生成过程分割开来,从而使得同样的一个建造过程生成具有不同的内部表象的产品对象。如果使用了建造者模式,那么用户只需要指定建造的类型就可以获得对象实例,而建造的过程和细节就不需要知道了。

传统的建造者模式有4种角色,Product(最终要生成的产品);Builder(建造者的抽象基类,其定义了构建产品的抽象步骤,不同的产品以不同的方式实现这些建造步骤,通常会包含一个返回最终产品的方法getProduct);ConcreteBuilder(Builder的具体实现类);Director(决定产品的构建过程,通常包含一个组装过程的方法construct,组装完成后就可以通过Builder的getProduct获得最终的产品)。使用传统的方式实现以上示例之后,其调用关系如下:

建造者通常在创建一些复杂的对象的时候使用,这些对象的内部构件间的构造顺序通常是稳定的,但内部构件的具体建造通常面临复杂的变化。建造者模式的好处就是使得建造代码与表示的代码分离,由于建造者隐藏了该产品是如何组装的,所以若要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。

4.原型模式

假设有一个写简历的需求,需要开发一个简历类,简历必须要有姓名,可以设置性别和年龄,可以设置工作经历,最后需要写三份简历。简历代码的最初步实现如下:

客户端调用的代码如下:

以上的方式写三份简历的话就需要经过三次实例化,当需要多次实例化时,这样的代码会非常繁琐。可以采用原型模式实现这种多次复制的过程,原型模式就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。使用原型模式实现写简历之后,代码如下所示:

客户端代码如下:

使用了原型模式之后,客户端的代码就不用重复去new新的对象。一般在初始化的信息不发生变化的情况下,使用原型模式通过克隆的方式创建对象是最好的方法,即隐藏了创建对象的细节,又对性能有大大的提高。它不需要重新初始化对象,而是动态地获得对象运行时的状态,省去了重复初始化对象的繁琐过程,整个流程简练了许多。

本文通过奶茶店下单、打开回收站、建造动画小人和写简历的例子,介绍了工厂方法模式、单例模式、建造者模式和原型模式的简单使用,展示了在不同的场景下这些经典的设计模式创建对象的方式,并通过代码的演变让读者能够直观地认识到引入设计模式之后对于代码或程序的提升。希望本文能够起到一个抛砖引玉的作用,读者通过本文能够初步感受到设计模式的魅力,并深入去了解,学习并体会设计模式的方法及思想,相信会对自己的编程能力有很大的提升。

感谢大家的观看,记得给小普点赞哦~

更多干货,⭐关注“极客小普冲呀”⭐,下期见!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
责任链设计模式是一种行为型设计模式,用于将请求的发送者和接收者解耦,使多个对象都有机会处理该请求。该模式将这些对象串成链,并沿着这条链传递请求,直到有一个对象能够处理它为止。 责任链模式的核心是定义一个处理请求的抽象类或接口,然后让多个具体的处理者对象继承或实现这个类/接口。每个具体的处理者对象都包含一个对下一个处理者对象的引用,形成一个链式结构。 当一个请求进入责任链时,责任链中的每个处理者都有机会处理该请求。如果可以处理请求,则进行处理;如果不能处理,则将请求传递给下一个处理者,直到有一个处理者能够处理它。 责任链模式的关键点是要找到合适的处理者顺序和条件。通常情况下,责任链模式适用于以下情况: 1. 有多个对象可以处理同一类型的请求,但具体由哪个对象来处理由运行时决定。 2. 不明确请求的接收者,希望请求在一个对象链中流动,直到被处理。 3. 需要动态地指定可以处理请求的对象集合。 使用责任链模式可以实现请求发送者和接收者的解耦,增加代码的灵活性和可扩展性。但同时也需要注意责任链的长度和效率问题,避免责任链过长或造成性能问题。 总结一下,责任链设计模式是一种将请求发送者和接收者解耦的设计模式,通过将多个处理者对象串成链,沿着这条链传递请求,直到有一个处理者能够处理它。这样可以增加代码的灵活性和可扩展性,适用于有多个对象可以处理同一类型请求的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值