设计模式能够帮助我们优化代码结构,让代码更优雅灵活。有哪些常见的设计模式?如何合理运用?本文分享作者对工厂模式、单例模式、装饰模式、策略模式、代理模式和观察者模式的理解,介绍每种模式的模式结构、优缺点、适用场景、注意实现及代码实现。
一 前言
最近在改造一些历史的代码,发现一个很明显的特点,大部分代码是记叙文,按照事件的发展过程将故事平铺直叙的讲解出来。
这种方式的好处是比较符合人类的思维习惯,一条主线讲到底,代码阅读起来没有太大难度,只要顺着藤就能摸到瓜,但是缺点也很明显,一旦故事线中需要插入一些新的元素,比如:加入一个新的人物角色、新的时间线,都会需要大量更改故事线以配合这个新元素的融入,甚至对原有文章造成破坏性的影响。
为了解决这个问题,人们总结出了很多种文章结构,例如:总-分结构,并列结构,总-分-总结构等等,有了这些结构,在加入新元素的时候,甚至不必考虑新元素与原故事情节的关联性,直接单拉一个分支故事线独立去讲就好了,只要能够在整体故事结束前,与汇聚到主线故事就可以了(是不是很像git?)。
在软件开发领域,也有很多这样的非常有用的实践总结,我们称之为设计模式。对于设计模式,大家都不陌生,随便找个人,估计都能讲出N个设计模式来,但是除了这些设计模式的概念,很多人不知道如何灵活运用这些设计模式。所以借这篇文章和大家共同学习设计模式的思想。
二 理解设计模式
我尽量用最通俗易懂的示例和语言来讲述我理解的设计模式,希望能对大家有所帮助。
另外也无需精通所有的设计模式,只要能够融汇贯通常见的设计模式,就能让你的代码变得优雅。就像程咬金只会三板斧,但是熟练度无人能及,照样能横行天下。
1 工厂模式(Factory)
简单工厂(Simple Factory)
小明追妹子的时候,请她喝了不少咖啡,她爱喝卡布奇诺,每次去咖啡店,只要跟服务员说“来杯卡布奇诺”就行了,虽然各家的口味有些不同,但是不管是星爸爸还是Costa,都能够提供卡布奇诺这种咖啡。这里的星爸爸和Costa就是生产咖啡的工厂。
(1)简单工厂模式结构
简单工厂模式包含如下角色:
结构图:
时序图:
(2)优缺点
工厂方法(Factory Method)
以前经常带老婆去优衣库(简单工厂)买衣服,就那么多款式,逛的次数多了,她就烦了。后来我改变策略,带老婆去逛商场(抽象工厂),商场里有各式品牌的店铺,不用我管,她自己就能逛上一整天。
区别于简单工厂,核心工厂类(商场)不再负责所有产品的创建,而是将具体创建的工作交给子类(服装店)去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口(门店),而不接触哪一个产品类应当被实例化这种细节。
(1)工厂方法模式结构
工厂方法模式包含如下角色:
结构图:
时序图:
工厂模式总结
(1)适用场景
输出的产品是标准品,谁来做都可以。
(2)举例
常见的数据库连接工厂,SqlSessionFactory,产品是一个数据库连接,至于是oracle提供的,还是mysql提供的,我并不需要关心,因为都能让我通过sql来操作数据。
(3)注意事项
项目初期,软件结构和需求都没有稳定下来时,不建议使用此模式,因为其劣势也很明显,增加了代码的复杂度,增加了调用层次,增加了内存负担。所以要注意防止模式的滥用。
(4)简单实现
- package FactoryMethod;
- public class FactoryPattern
- {
- public static void main(String[] args)
- {
- Factory factory = new ConcreteFactoryA();
- Product product = factory.createProduct();
- product.use();
- }
- }
- //抽象产品:提供了产品的接口
- interface Product
- {
- public void use();
- }
- //具体产品A:实现抽象产品中的抽象方法
- class ConcreteProductA implements Product
- {
- public void use()
- {
- System.out.println("具体产品A显示...");
- }
- }
- //具体产品B:实现抽象产品中的抽象方法
- class ConcreteProductB implements Product
- {
- public void use()
- {
- System.out.println("具体产品B显示...");
- }
- }
- //抽象工厂:提供了厂品的生成方法
- interface Factory
- {
- public Product createProduct();
- }
- //具体工厂A:实现了厂品的生成方法
- class ConcreteFactoryA implements AbstractFactory
- {
- public Product createProduct()
- {
- System.out.println("具体工厂A生成-->具体产品A.");
- return new ConcreteProductA();
- }
- }
- //具体工厂B:实现了厂品的生成方法
- class ConcreteFactoryB implements AbstractFactory
- {
- public Product createProduct()
- {
- System.out.println("具体工厂B生成-->具体产品B.");
- return new ConcreteProductB();
- }
- }
2 单例模式(Singleton)
韦小宝有7个老婆,但是每个都只有他这一个老公,他的所有老婆叫老公时,指的都是他,他就是一个单例。
单例模式结构
单例模式包含如下角色:
结构图:
时序图:
优缺点
应用场景
适合需要做全局统一控制的场景,例如:全局唯一的编码生成器。
注意事项
只对外提供公共的getInstance方法,不提供任何公共构造函数。
简单实现
- public class Singleton
- {
- private static volatile Singleton instance=null; //保证 instance 在所有线程中同步
- private Singleton(){} //private 避免类在外部被实例化
- public static synchronized Singleton getInstance()
- {
- //getInstance 方法前加同步
- if(instance == null)
- {
- instance = new Singleton();
- }
- return instance;
- }
- }
3 装饰模式(Decorator)
大学毕业,想要送给室友一个有纪念意义的礼物,就找到一张大家的合照,在上面写上“永远的兄弟!”,然后拿去礼品店装了个相框,再包上礼盒。这里的我和礼品店都是装饰器,都没有改变照片本身,却都让照片变得更适合作为礼物送人。
装饰模式结构
装饰模式包含如下角色:
结构图:
时序图:
优缺点
适用场景
注意事项
简单实现
- package decorator;
- public class DecoratorPattern
- {
- public static void main(String[] args)
- {
- Component component = new ConcreteComponent();
- component.operation();
- System.out.println("---------------------------------");
- Component decorator = new ConcreteDecorator(component);
- decorator.operation();
- }
- }
- //抽象构件角色
- interface Component
- {
- public void operation();
- }
- //具体构件角色
- class ConcreteComponent implements Component
- {
- public ConcreteComponent()
- {
- System.out.println("创建具体构件角色");
- }
- public void operation()
- {
- System.out.println("调用具体构件角色的方法operation()");
- }
- }
- //抽象装饰角色
- class Decorator implements Component
- {
- private Component component;
- public Decorator(Component component)
- {
- this.component=component;
- }
- public void operation()
- {
- component.operation();
- }
- }
- //具体装饰角色
- class ConcreteDecorator extends Decorator
- {
- public ConcreteDecorator(Component component)
- {
- super(component);
- }
- public void operation()
- {
- super.operation();
- addBehavior();
- }
- public void addBehavior()
- {
- System.out.println("为具体构件角色增加额外的功能addBehavior()");
- }
- }
4 策略模式(Strategy)
男生追妹子时,一般都会用到这种模式,常见的策略有这些:约会吃饭;看电影;看演唱会;逛街;去旅行……,虽然做的事情不同,但可以相互替换,唯一的目标都是捕获妹子的芳心。
策略模式结构
结构图:
时序图:
优缺点
试用场景
一个系统需要动态地在几种可替换算法中选择一种。不希望使用者关心算法细节,将具体算法封装进策略类中。
注意事项
一定要在策略类的注释中说明该策略的用途和适用场景。
简单实现
- package strategy;
- public class StrategyPattern
- {
- public static void main(String[] args)
- {
- Context context = new Context();
- Strategy strategyA = new ConcreteStrategyA();
- context.setStrategy(strategyA);
- context.algorithm();
- System.out.println("-----------------");
- Strategy strategyB = new ConcreteStrategyB();
- context.setStrategy(strategyB);
- context.algorithm();
- }
- }
- //抽象策略类
- interface Strategy
- {
- public void algorithm(); //策略方法
- }
- //具体策略类A
- class ConcreteStrategyA implements Strategy
- {
- public void algorithm()
- {
- System.out.println("具体策略A的策略方法被访问!");
- }
- }
- //具体策略类B
- class ConcreteStrategyB implements Strategy
- {
- public void algorithm()
- {
- System.out.println("具体策略B的策略方法被访问!");
- }
- }
- //环境类
- class Context
- {
- private Strategy strategy;
- public Strategy getStrategy()
- {
- return strategy;
- }
- public void setStrategy(Strategy strategy)
- {
- this.strategy=strategy;
- }
- public void algorithm()
- {
- strategy.algorithm();
- }
- }
5 代理模式(Proxy)
淘宝店客服总是会收到非常多的重复问题,例如:有没有现货?什么时候发货?发什么快递?大量回答重复性的问题太烦了,于是就出现了小蜜机器人,他来帮客服回答那些已知的问题,当碰到小蜜无法解答的问题时,才会转到人工客服。这里的小蜜机器人就是客服的代理。
代理模式结构
代理模式包含如下角色:
结构图:
时序图:
优缺点
试用场景
理论上可以代理任何对象,常见的代理模式有:
简单实现
- package proxy;
- public class ProxyPattern
- {
- public static void main(String[] args)
- {
- Proxy proxy = new Proxy();
- proxy.request();
- }
- }
- //抽象主题
- interface Subject
- {
- void request();
- }
- //真实主题
- class RealSubject implements Subject
- {
- public void request()
- {
- System.out.println("访问真实主题方法...");
- }
- }
- //代理
- class Proxy implements Subject
- {
- private RealSubject realSubject;
- public void request()
- {
- if (realSubject==null)
- {
- realSubject=new RealSubject();
- }
- preRequest();
- realSubject.request();
- afterRequest();
- }
- public void preRequest()
- {
- System.out.println("访问真实主题之前的预处理。");
- }
- public void afterRequest()
- {
- System.out.println("访问真实主题之后的后续处理。");
- }
- }
6 观察者模式(Observer)
出差在外,想了解孩子在家的情况,这时候只要加入“相亲相爱一家人”群,老爸老妈会经常把孩子的照片和视频发到群里,你要做的就是作为一个观察者,刷一刷群里的信息就能够了解一切了。
观察者模式结构
观察者模式包含如下角色:
结构图:
时序图:
优缺点
适用场景
适用于一对多的的业务场景,一个对象发生变更,会触发N个对象做相应处理的场景。例如:订单调度通知,任务状态变化等。
注意事项
避免观察者与被观察者之间形成循环依赖,可能会因此导致系统崩溃。
简单实现
- package observer;
- import java.util.*;
- public class ObserverPattern
- {
- public static void main(String[] args)
- {
- Subject subject = new ConcreteSubject();
- Observer obsA = new ConcreteObserverA();
- Observer obsb = new ConcreteObserverB();
- subject.add(obsA);
- subject.add(obsB);
- subject.setState(0);
- }
- }
- //抽象目标
- abstract class Subject
- {
- protected List
observerList = new ArrayList (); - //增加观察者方法
- public void add(Observer observer)
- {
- observers.add(observer);
- }
- //删除观察者方法
- public void remove(Observer observer)
- {
- observers.remove(observer);
- }
- public abstract void notify(); //通知观察者方法
- }
- //具体目标
- class ConcreteSubject extends Subject
- {
- private Integer state;
- public void setState(Integer state){
- this.state = state;
- // 状态改变通知观察者
- notify();
- }
- public void notify()
- {
- System.out.println("具体目标状态发生改变...");
- System.out.println("--------------");
- for(Observer obs:observers)
- {
- obs.process();
- }
- }
- }
- //抽象观察者
- interface Observer
- {
- void process(); //具体的处理
- }
- //具体观察者A
- class ConcreteObserverA implements Observer
- {
- public void process()
- {
- System.out.println("具体观察者A处理!");
- }
- }
- //具体观察者B
- class ConcreteObserverB implements Observer
- {
- public void process()
- {
- System.out.println("具体观察者B处理!");
- }
- }
【本文为专栏作者“阿里巴巴官方技术”原创稿件,转载请联系原作者】
戳这里,看该作者更多好文
网站标题:如何理解这6种常见设计模式?
网页URL:http://www.shufengxianlan.com/qtweb/news26/359876.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联