写在前面

评判一个程序员是否优秀,就是 show me the code。优秀的代码可读性强,高内聚低耦合,可扩展。想要写优秀的代码,做个优秀的程序员,就需要多看看大牛写的开源框架,吸取其中的精华,多学学设计模式,除此之外,没有任何其他捷径。

设计模式主要分为创建型模式结构型模式行为型模式三种类型。

工厂方法(Factory method pattern)

定义一个创建对象的接口,让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行,它属于创建型模式。

工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种类型的对象。这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象。

工厂通常是一个用来创建其他对象的对象。工厂是构造方法的抽象,用来实现不同的分配方案。

维基百科工厂方法的例子

// 定义了 Button 如何创建
public interface Button{}
// 实现了 WinButton
public class WinButton implements Button{}
// 实现了 MacButton
public class MacButton implements Button{}// 创建 Button 的工厂类
public interface ButtonFactory {Button createButton();
}
// 真正创建 WinButton 的实现类,实现了 ButtonFactory
public class WinButtonFactory implements ButtonFactory {@Overridepublic static Button createButton(){return new WinButton();}
}
// 真正创建 MacButton的实现类,实现了 ButtonFactory
public class MacButtonFactory implements ButtonFactory {@Overridepublic static Button createButton(){return new MacButton();}
}
复制代码

抽象工厂模式(Abstract factory pattern)

将一组具有同一主题的单独的工厂封装起来。在使用中,使用方需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一方法的具体对象。它属于创建型模式。

抽象工厂就好像是对工厂方法的一种扩展,有个产品族的概念,也就是一堆产品。上面的工厂方法就一个产品(Button),而下面抽象工厂的例子里有两个产品(Button和 Border)。

抽象工厂的优点:
具体产品从客户代码中被分离出来。
容易改变产品的系列。
将一个系列的产品族统一到一起创建。

抽象工厂的缺点:
在产品族中扩展新的产品是很困难的,它需要修改抽象工厂的接口。

维基百科抽象工厂的例子

public interface Button {}
public interface Border {}public class WinButton implements Button {}
public class WinBorder implements Border {}public class MacButton implements Button {}
public class MacBorder implements Border {}public interface AbstractFactory {Button createButton();Border createBorder();
}public class WinFactory {@Overridepublic static Button createButton() {return new WinButton();}@Overridepublic static Border createBorder() {return new WinBorder();}
}public class MacFactory {@Overridepublic static Button createButton() {return new MacButton();}@Overridepublic static Border createBorder() {return new MacBorder();}
}复制代码

构建模式(Builder pattern)

当构建一个复杂对象时,就可以使用建造者模式。它实际上就是传入一个参数,然后返回对象本身,方便下一个属性或者参数来构建。可以按需构建对象,可扩展性强。它属于创建型模式。

在 JDK 中,StringBuilder 类的 append() 方法就是一个很好的构建模式例子。

    // java.lang.StringBuilder@Overridepublic StringBuilder append(CharSequence s) {super.append(s);return this;}
复制代码

原型模式(Prototype pattern)

它的特点在于通过 复制 一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的原型,这个原型是可定制的。它属于创建型模式。

原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效,它们实际上就是命名不一样的同类数据。

在 JDK 中,Object 类中的 clone() 方法就是典型的原型模式。

    //在具体的实现类里可以直接重写 clone() 方法protected native Object clone() throws CloneNotSupportedException;复制代码

单例模式(Singleton pattern)

不管在任何时候,获取一个对象时只会返回同一个实例。通常我们在都读取配置文件时,文件里的内容是不变的,因此我们就可以使用单例模式来实现。它属于创建型模式。

单例模式很简单,只需要三步就完成,下面是 JDK 里的 Runtime 类实现的单例模式。

public class Runtime {// 1.new 一个私有的静态的 Runtime 实例private static Runtime currentRuntime = new Runtime();// 2.返回当前应用的 Runtime 实例public static Runtime getRuntime() {return currentRuntime;}// 3.私有化构造方法,不允许在其它类构造 Runtime 实例private Runtime() {}
}
复制代码

适配器模式(Adapter pattern)

适配器模式也称作包装(wrapper),它属于结构型模式。

它的作用是把原本两个不兼容的接口通过一个适配器或者包装成兼容的接口,然后它们可以一起工作。例如我们的手机数据线,就好比是一个适配器,一端是 USB接口,一端是 Type-C 或者 Lightning 接口,本来它们是不能一起工作的,但我们用这跟数据线(适配器)就可以让它们协同工作了。

它的优点:
1.可以让任何两个没有关联的接口一起工作。
2.提高了接口的复用。
3.增加了接口的透明度。
4.灵活性好。

它的缺点:
1.过多地使用适配器,会让系统非常零乱,不易整体进行把握。
2.由于 JAVA 只能继承一个类,所以最多只能适配一个适配者类,而且目标类必须是抽象类。

在 JDK 中,Arrays 类中的 asList(T... a) 方法就是适配器模式的例子,把一个数组转换为一个集合。

    public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}
复制代码

在 JDK 中,Collections 工具类的 list() 方法把枚举转集合。

    public static <T> ArrayList<T> list(Enumeration<T> e) {ArrayList<T> l = new ArrayList<>();while (e.hasMoreElements())l.add(e.nextElement());return l;}
复制代码

当然,这上面两个例子是非常简单的,好像看不出来使用了任何的设计模式,跟我们平时使用的转换一模一样。这里只是一个理念的介绍,实际上,在使用中是用一个中间的 Adapter 类来做兼容或者包装的。

桥接模式(Bridge pattern)

将抽象与其实现分离,以便两者可以独立变化。它属于结构型模式。

当一个类经常变化时,面向对象编程的特性变得非常有用,因为可以用最少的关于程序的先验知识来容易地改变程序的代码。当类和它经常变化时,桥模式很有用。类本身可以被认为是抽象,类可以作为实现来做。桥模式也可以被认为是两层抽象。

它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

它的优点:
1.抽象和实现分离开。
2.优秀的扩展能力。
3.实现细节对调用方透明。

它的缺点:
桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,需要针对抽象进行设计与编程,加深编程难度。

这是个生产不同车辆和需要不同生产流程的例子。首先,定义一个车辆(Vehicle)的抽象接口,里面有个生产车辆的对应流程集合和一个生产的抽象方法。然后是自行车(Bike)和汽车(Car)对抽象接口的实现。然后定义一个生产车辆需要的流程(WorkShop),它有两个实现 ProduceWorkShop 和 TestWorkShop。最后,main 方法的代码就是对这个桥接模式的使用方式。

这种设计模式的好处是方便添加一种车巴士(Bus),只需要继承 Vehicle 类。也非常方便的添加一种生产流程喷漆(PaintWorkShop),只需要继承 WorkShop 类即可,扩展性很高。

//车辆的抽象接口
public abstract class Vehicle {//protected List<WorkShop> workshops = new ArrayList<WorkShop>();public Vehicle() {super();}public boolean joinWorkshop(WorkShop workshop) {return workshops.add(workshop);}public abstract void manufacture();
}//自行车的实现
public class Bike extends Vehicle {@Overridepublic void manufacture() {System.out.println("Manufactoring Bike...");workshops.stream().forEach(workshop -> workshop.work(this));}
}
//汽车的实现
public class Car extends Vehicle {@Overridepublic void manufacture() {System.out.println("Manufactoring Car");workshops.stream().forEach(workshop -> workshop.work(this));}
}
//生产车的抽象接口
public abstract class WorkShop {public abstract void work(Vehicle vehicle);
}
//制造车的实现
public class ProduceWorkShop extends WorkShop {public ProduceWorkShop() {super();}@Overridepublic void work(Vehicle vehicle) {System.out.print("Producing... ");}
}
//测试车的实现
public class TestWorkShop extends WorkShop {public TestWorkShop() {super();}@Overridepublic void work(Vehicle vehicle) {System.out.print("Testing... ");}
}
//使用
public class Main {public static void main(String[] args) {//生产一辆自行车Vehicle bike = new Bike();bike.joinWorkshop(new ProduceWorkShop());bike.manufacture();//生产一辆汽车Vehicle car = new Car();car.joinWorkshop(new ProduceWorkShop());car.joinWorkshop(new TestWorkShop());car.manufacture();}
}
复制代码

最后,单看设计模式例子是非常简单的,但有时候写代码时却用不上这些设计模式,这是一种写代码思维上的转变。也就是在写代码之前,我们需要根据业务场景思考,那种设计模式适合使用,记住使用设计模式的最终目的是代码可读性强,高内聚低耦合,可扩展。这是一种思维上的转变,多思考在动手,熟能生巧。

PS:
清山绿水始于尘,博学多识贵于勤。
微信公众号:「清尘闲聊」。
欢迎一起谈天说地,聊代码。

通熟易懂的设计模式(一)相关推荐

  1. 史上最通熟易懂的检索式聊天机器人讲解

    喵喵喵,一不小心又匿了三个月,突然诈尸害不害怕( ̄∇ ̄) 小夕从7月份开始收到第一场面试邀请,到9月初基本结束了校招(面够了面够了T_T),深深的意识到今年的对话系统/chatbot方向是真的超级火呀 ...

  2. 为什么java抗并发_用最通熟易懂的话说明,为什么要使用java并发编程

    老早之前的计算机只有一个处理器,而 一个处理器在同一时刻只能处理一条指令 ,换句话说,我们的代码需要一行一行的按顺序被计算机执行,计算机只能把一个程序完整的执行完,然后再执行第二个程序.所以计算机专业 ...

  3. 通熟易懂的 Elasticsearch入门

    导语 小猴周末在家看了综艺节目<王牌对王牌>,对里面的猜歌曲环节饶有兴趣,主持人随便说一个字或词语,选手必须唱出包含该字或者词语的歌曲.小猴觉得太有意思了,今天上班准备和他猴哥过两招. E ...

  4. 设计模式23种通熟解释和简明教程

     1.factory(工厂)追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德 基,只管向服务员说"来四个鸡翅" ...

  5. 通熟理解urL和urI的区别

    转载自:https://blog.csdn.net/simplebam/article/details/72644094 关于URL和URI的区别,个人见解. 初学java,最近被一个概念搞得头晕脑胀 ...

  6. Spring Boot入门操作(轻熟易懂)

    这里写目录标题 项目结构介绍 pom包介绍 编写代码:实现一个HelloWorld 运行访问: 单元测试 Spring Boot的核心 项目结构介绍 1.Spring Boot的基础结构共三个文件: ...

  7. 震惊!小猪的设计模式初涉总结!纯干货~

    震惊!小猪的设计模式初涉总结!纯干货~ 标签: 知识点总结 描述性文字 今年一月初有了离职的念头后,就盘算着把设计模式给过一遍,索性就开了一个新的系列: <如何让孩子爱上设计模式>.在编写 ...

  8. 同一局域网中ping 通 Ubuntu 与 win10

    ubuntu 与 win的互ping 需求描述 详细步骤 第一步:查看两台服务器各自的ipv4地址 第二步:ping 对方的ipv4地址 局域网LAN 以太网 ping命令 iPv4地址 ppp适配器 ...

  9. python自学书籍推荐豆瓣-【转】如果有人让你推荐Python技术书,请让他看这个列表...

    入门级 <Head First Python>+ 入门级 + 微信49票 + 豆瓣评分 9.5 推荐语: 66:浅显易懂,编排的顺序特别,有大量插图.对话,不感觉枯燥 古心:通熟易懂,配有 ...

最新文章

  1. 第四天 用户管理和服务管理
  2. PHP APM fiery 更新 v0.5.8.0
  3. 【学术相关】近5年十大最具影响力的 AI 论文,你知道几个?
  4. 大剑无锋之大数据面试题第一套(选择题)
  5. php根据键值去除数组中的某个元素_php数组删除元素 删除指定键值元素
  6. win7睡眠,休眠的区别
  7. [RK3399][Android7.1] 基于regmap的I2C实现方法
  8. FTP 文件上传跟下载
  9. AngularJS开发指南10:AngularJS依赖注入的详解
  10. python熊猫烧香_熊猫烧香完整源代码
  11. 调用阿里API实现图片验证码识别
  12. 地理围栏 | EXCEL表格中分析轨迹坐标是否在设定的围栏范围内
  13. 北理工嵩天Python语言程序设计笔记(10 Python计算生态概览)
  14. stl文件 python_用Python从STL文件绘制2D图像
  15. Soul瞬间发布长录音教程
  16. 南邮 OJ 1733 跳棋
  17. php写的代码点击提交没效果,PHP代码实现提交虚假数据给百度统计
  18. C语言——占位符【标志字符】
  19. zlibirary官网入口全新获取方式,zlibirary最新地址检测
  20. 基于Teager-Kaiser能量算子和深度置信网络的往复式压缩机阀门故障诊断方法

热门文章

  1. 微信群服务器失败是什么原因,为什么微信群转让群主失败?微信群转让群主方法是什么?...
  2. SwinUNet2022
  3. 搜索问题之状态空间搜索(状态压缩+记忆化搜索+ BFS)
  4. 使用freemarker生成word文档(包含遍历多条数据、图片)
  5. 使用Two.js绘制2D图形的初学者指南
  6. 牛客网大厂在线笔试输入输出练习python3版
  7. 使用 FFmpeg 转换视频/音频格式 | 开源 免费 | 不用套壳软件
  8. redis无法远程连接的所有解决方案大全
  9. 工大助手电费查询接口讲解
  10. 终于有人把Web 3.0和元宇宙讲明白了