为什么要学习和使用设计模式啊?正确使用设计模式,不仅能让项目开发效率更高,也能让项目更容易维护。对于程序员来说,设计模式是最简单的东西,但正确运用起来又不是那么简单。设计模式是从实际开发中总结出来的编码经验,它与业务开发是辩证统一、互不分离的。本篇基于java说一下设计模式与实际开发的关系以及举例部分简单的应用。
基础
学习设计模式之前我们先要了解一下设计模式诞生和使用的基础(熟悉的同学可以跳过这一部分):
a.面向对象编程(OOP)
面向对象编程也叫物件导向编程。学习面向对象语言的时候,都会听过这么一句话,世界皆对象。面向对象思想把世界万物看作对象、看作物件来进行描述,它是一种世界观,既然是世界观,必然会影响到我们的方法论,那就是对象操作。
b.面向对象的特性
继承:子继承父,子类继承父类,继承描述的是子类会继承父类的特点(属性和行为)。如哈士奇狗妈妈生了小狗,小狗身上就会体现出狗妈妈的特征:哈士奇的模样、哈士奇的二。
多态:多态描述的是同一类事物,在不同的实现里面,它们的共有行为可以表现得有所不同。比如在会飞的东西里面,小鸟可以直接振翅高飞,飞机则需要先启动引擎,然后助跑再进行起飞,它们飞的方式就不同了。
封装:封装性赋予了对象一种权限的概念,分别有公开、私有、保护三种权限。它影响了外部世界对这个对象行为的可见性和可操作性,隐藏了对象行为的具体执行步骤。怎么理解呢?两家不同的外卖餐厅,我各点了一份炒牛肉,两份卖相都挺好的,但是实际上有一家外卖是用鲜牛肉现切外加炭火炒的,一家是用冰鲜牛肉然后加很多味精一大锅炒出来的,然鹅我是不知道两份炒牛肉到底是怎么做出来的,这是因为我对餐厅这个对象的炒菜步骤不可见。如果我是这个冰鲜牛肉餐厅的老板,我就可以叫厨房改用新鲜肉,但是我只是个顾客,无法操作这个餐厅对象,没有修改厨房炒菜步骤的权限。
c.面向对象6个基本原则(这部分展开讲的话有点太长,感兴趣的同学自行搜索一下)
单一职责原则:一个类应该只负责一种事情,不应该拥有太多的职责;
开放封闭原则:对修改关闭,对拓展开放;主要说的指不要去修改底层的基础设施,而底层要具有拓展性,可以在高层对其进行拓展;
里氏替换原则:一个基类可以替换成它的子类而不影响程序运行;
依赖倒置原则:程序应该依赖于抽象接口,不要依赖于具体实现;
接口分离原则:过于庞大的接口应该拆分为多个更小的接口;
迪米特法则:两个类相互作用,它们之间知道对方的信息越少越好。
d.抽象
将一系列事物的共性总结简化出来,就是抽象。例如猫和狗,它们的抽象就是动物;飞机和鸟,它们的抽象就是会飞的东西。
以上便是我认为的设计模式诞生和使用的基础,接下来终于来到正文!
正文
基本的设计模式有23种,根据分类分为创建型模式、结构型模式和行为型模式三类。
看一下都有些什么模式:
创建型:工厂模式、抽象工厂模式、建造者模式、原型模式、单例模式
结构型:适配器模式、组合模式、代理模式、享元模式、外观模式、桥接模式、装饰模式
行为型:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式
接下来举几个运用设计模式对代码进行改造的例子:
第一个例子是我们在androidMPV模式中经常遇到的情况,有几个页面都是一样的,于是我们想要复用同一个页面进行显示,但是它们逻辑和数据常常会有所差别,很自然地会创建出一个type变量根据它的参数进行if或者switch进行判断来进行不同的逻辑,所以往往写出来的代码是这样的:
流程图:
代码:
这个例子中操作方法数量虽然多了,但是设想一下这个页面逻辑多起来,然后几乎每个方法都要进行进行一次switch,接手这样的代码,你崩不崩溃?下一次又增加一个新的type,要在每一个switch里面都加一个case,万一某一个switch加少了,程序分分钟崩溃;想要不崩溃,只能花不少时间去每个方法检查检查有没有遗漏了。
天啊检查来检查去太花时间了啦!还要上下慢慢滑页面看代码,好几百行呢!真让人受不了!
怎么办啊?
赶紧改造它呗!
我们再看一下前面的流程图,每次进行页面类型判断然后进行的一系列操作,是不是可以看作是一个操作呢?
这个switch下类型1、类型2和类型3都执行了一个综合操作,如果我们把综合操作都称为work(),那么就是有三个work()的不同实现,同样地把各个方法里的switch都做同样的处理,可以发现这些switch后边的执行只不过都是同名方法的不同实现而已,完全可以把它们抽象出来,把同种case的执行方法都封装到一个类里边。
于是我们抽象出IWork接口,写出它的3个实现类,分别对应3个type:
Presenter的部分就简化成了这样:
只有最开始setType()的时候进行了一次类型判断,其他地方的都用了IWork的实现进行操作,这样就避免了类里处处switch,增加新的type也只需要再写一个IWork的实现,再也不用去看哪里没有增加switch这样的判断了。程序也变得简洁,真让人心情舒畅~
总结一下我们在这个例子中的处理,首先我们首先看出了程序里面的共性,抽象出IWork接口(抽象),然后我们类中依赖了接口(依赖倒置),通多调用接口的方法,利用接口的不同实现去处理数据(多态),从而实现了代码的优化。这就写出了状态模式。至于代码的进一步优化,可以再使用工厂模式去创建IWork的实例。利用好编码基础,分分钟写出设计模式。
今天的例子讲到这里,下一篇继续举例更多的实际思路和应用。