zoukankan      html  css  js  c++  java
  • 漫谈设计模式

      什么是设计模式?(以前一直听说,感觉很高大上)设计模式是对一系列OO设计中的经验进行复用。最终的目的是提高系统的复用、易维护、易扩展。软件系统需求总是在不断变化,面对的情况也会变化(不仅仅是因为产品狗……)。在软件开发后,大量时间会进行维护。设计模式就是尽量设计能够适应变化的系统,使系统更有弹性,面对变化更能游刃有余。将设计模式的思想融合到自己的大脑,面对不同的需求应用对应的设计模式,就能设计出比较流弊(NB)的结构,提升代码质量。

      接下来,我们就来聊聊各个设计模式吧。

    一、策略模式(Strategy Pattern)

      策略模式是什么京东?先看看定义:“定义算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户”。……嗯……还是不知道什么意思。大概翻译一下:策略模式就是让方法的实现独立于方法的使用者,使得方法的变化不会影响使用者。打个比方:比如一个武士(使用者),具备一个“使用武器”的技能(方法),但是使用什么武器呢?这个武器可能是刀枪棍棒,不一定。那我们就把这个“使用武器”这个方法独立于武士,把二者的实现分开。

      定义大概就是那样。我们来看看一个具体的应用场景。

      场景:我们定义一个鸭子类,鸭子具有飞行的方法。但是有可能不同的鸭子飞的方法不一样,有的像普通鸭子那样飞,有的像飞机那样飞(发挥一点想象力)。因此“飞”这个方法就是容易改变的。因此我们就将这个方法进行抽象,将其与鸭子的实现进行分离,尽量针对接口编程而非实现编程。所以将飞行方法用一个接口进行封装,具体的不同的飞行类实现接口。然后采用组合的方式将飞行类包含到鸭子类中。这样就使得方法和使用者独立开来。

      

    二、观察者模式(Observer)

      观察者模式就比较容易明白了。先看看定义:“在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新”。定义不难理解,但是什么情况下使用观察者模式呢?应该也不难想到,比如当多个或者一个对象需要访问同一个数据源,共享一个数据的时候(一对多),那就需要采用观察者模式。同样,我们具体用一个场景来分析。

      场景:我们有一个气象数据收集站(很不想用书上的这个例子……),会时不时的更新气象站手机的数据,如温度啊,风向啊,污染指数啊,PM2.5之类的。现在我们开发三个APP,这三个APP都需要获取气象站的数据,然后按照自己的业务逻辑处理获得的数据。

      那很明显,上述就是一个一对多的例子,适合用观察者模式。观察者模式有一些固定的组件,先看图。

      可以看到,观测着模式分为两个部分:对象subject和gu观察者Observer。对象就是我们需要共享的资源,观察者就是要使用数据的客户。作为一对多,要实现对象在更新的时候对所有观测者的通知,因此对象那边就需要对观察者进行管理,知道有哪些观察者,因此对象需要提供对观察者的加入register、退出remove、群发消息notify的功能。这里我们用接口实现Subject。

      对于观察者,我们需要给对象提供更新数据的方法,这样对象才知道以什么方式来通知观察者数据。因此观察者统一实现Observer接口。这样,观察者和对象就建立了联系。

      在java中,有对观察者模式的实现,在java.util.Observe*中实现。但是他的对象管理是用类实现的,WeatherDate是继承父类。这样就没有定义为接口好。因为java不支持多继承,如果WeatherData还想继承其他类怎么办,同时违背了“多组合,少继承”的原则。

    在jDK源码中,很多都运用了观察者模式,如Swing,RMI等等。

    三、装饰者模式(Decorator)

      装饰者模式也是比较明确的设计模式。首先看定义:“动态地将责任附加到对象上。想要扩展功能,装饰着提供有别于继承的另一种选择”。简单解释一下,即当你想对某一种现有的东西进行扩展,但是又不能修改他的代码,那就对他进行包装,把你需要新加上去的功能“装饰”上去。举个栗子

      场景:你在面馆里点面(终于不用书上的例子了!),然后你就看菜单啊。菜单这样写着:经典兰州拉面(8¥),火腿(1¥),鸡蛋(2¥),两片羊肉(3¥)。我们现在要给这个餐厅做一个餐厅点菜管理系统,需要对每次客人点的菜进行记录,比如点的什么面啊,加了什么其他的没啊。因为有的时候,有的人要面+鸡蛋,有的人面+火腿,有的人面+鸡蛋+火腿(太铺张浪费了……)。很明显,这个场景里面有一个不变的,或者说基本的,就是那碗面。而要变化的就是要不要加其他的东西。往面中加其他东西的过程就是在对那碗面个性化进行“装饰”。(怎么感觉自己好啰嗦……)那我们怎么应用装饰者模式来设计这个场景呢

      在装饰者模式中,由两个部分组成。一个叫组件(被装饰者),一个叫装饰者。二者都是继承至同一个父类。这里用到继承,不是为了需要继承行为,而是需要继承同一种模式,使得组件和装饰者能够进行结合(因为都属于一类)。在此应用场景中,兰州拉面本身为需要被装饰的组件,而加的蛋和肠作为装饰者。

         当需要进行使用时,将二者进行结合 经典兰州拉面 拉面 = new 火腿肠(经典兰州拉面)。这样就等于新建了一个加了肠的兰州拉面,通过调用cost可以计算加了肠的兰州拉面多少钱。可以像上面一样通过不同的包装进行有选择的扩展经典兰州拉面。这样就避免了使用继承。
      在java.io中就使用了大量的装饰者模式。装饰者模式,就是体现了我们设计的一个重要原则,即开闭原则:对扩展开放,对修改闭合
      但是对于装饰者模式,存在的问题就是如果存在依赖于组件本身的类型(因为加了装饰者就会改变本身的类型),那就不好操作了。
     

    四、工厂模式 

      工厂模式应该说是用的比较多的一种设计模式。在工厂模式中,分为两类,一种是工厂方法模式,一种是抽象工厂模式。二者还是有一定的区别。

      我们首先看看工程方法模式(Factory Method Pattern)。定义:“定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类”。好像不是很直观。没关系,老规矩,以实例分析,看类图。

      场景:有面馆生产面。有做方便面的,有做拉面的。都是首先订外卖的订一种面, 然后对应的面馆就做面。

      工厂方法的特点就是首先通过抽象类的编写,固定了不同面馆面的模式。通过继承基类,在子类中具体实例化自己的业务逻辑。

  • 相关阅读:
    一个思绪凌乱的前端
    如何将你的github仓库部署到github pages(github.io博客)
    聊一聊前端系列篇
    Centos7升级gcc极简教程
    Pycharm报错连接linux服务器报错:Could not verify `ssh-rsa` host key with fingerprint
    基于Pytorch的简单小案例
    windows安装Pytorch报错:from torch._C import * ImportError: DLL load failed: 找不到指定的模块”解决方案
    scrapy抓取豆瓣电影相关数据
    scrapy结合selenium抓取武汉市环保局空气质量日报
    scrapy抓取国家社科基金项目数据库
  • 原文地址:https://www.cnblogs.com/ren-jie/p/5453078.html
Copyright © 2011-2022 走看看