精华内容
下载资源
问答
  • MVC设计模式思想简述

    千次阅读 2019-03-22 18:10:53
    设计模式不是一种方法或技术,而是一种思想。 语言无关、平台无关。例如:孙子兵法,三十六计等。 设计模式共23种,常用的4—6种 工厂模式 代理模式 单例模式 适配器模式 MVC设计模式 详见:...
    1. 什么是设计模式
      设计模式是一套被反复使用、多人知晓的,并经过分类编目的代码设计经验的总结。
      设计模式不是一种方法或技术,而是一种思想。
      语言无关、平台无关。例如:孙子兵法,三十六计等。

    2. 设计模式共23种,常用的4—6种
      工厂模式
      代理模式
      单例模式
      适配器模式
      MVC设计模式

    3. MVC设计模式
      M—Model:模型层,用于数据封装(实体类)和业务逻辑(业务类或DAO类),主要通过JavaBean来实现。
      V—View:视图层,用于提供与用户交互的界面,动态展示数据,web项目中主要通过JSP,vue,等前端框架来实现,也可通过app方式实现。
      Controller:控制器层,用于处理请求并响应,主要通过Servlet,SpringMvc等框架来实现。

    4. MVC核心思想:分离。

    5. MVC的核心是控制器Controller,控制器的作用:
      接收请求参数
      控制业务逻辑(调用业务类)
      控制程序的流向(请求转发和重定向)

    6. 不能一个请求对应一个Servlet
      两种解决方案:
      方案一:

    //以下是伪代码
    Servlet{
    				service(){
    					if(operate.equals("aa")){
    						处理aa请求
    					}else if(operate.equals("bb")){
    						处理bb请求
    					}
    					...
    				}
    				
    			}
    

    方案2:通过DispatchServlet实现“大C+小c模式,类似于层级管理模式”

    //伪代码
    			XxxServlet extends DispatchServlet{
    				处理请求1();
    				处理请求2();
    				。。。
    			}
    

    DispatchServlet

    public class DispatchServlet extends HttpServlet {
    	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		String flag=request.getParameter("flag");
    		try {
    			Method m=this.getClass().getDeclaredMethod(flag, HttpServletRequest.class,HttpServletResponse.class);//通过反射技术拼出方法
    			m.invoke(this, request,response);//执行方法
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    }
    
    展开全文
  • 设计模式 思想 模式 原则 设计模式 思想 模式 原则 设计模式 思想 模式 原则
  • 如何通俗理解设计模式及其思想

    万次阅读 多人点赞 2018-07-08 20:36:52
    本文由 玉刚说写作平台 提供写作赞助 原作者:却把清梅嗅 ... 版权声明:本文版权归微信公众号 玉刚...数据结构,算法,设计模式被认为是程序员必备技能的三叉戟,如果说编程语言的语法特性和业务编码能力是【术】,...

    本文由 玉刚说写作平台 提供写作赞助
    原作者:却把清梅嗅
    原文地址:https://mp.weixin.qq.com/s/T6ZCQRydzFgVUezlywC8Zw
    版权声明:本文版权归微信公众号 玉刚说 所有,未经许可,不得以任何形式转载!

    术与道


    数据结构,算法,设计模式被认为是程序员必备技能的三叉戟,如果说编程语言的语法特性和业务编码能力是【术】,那么这三者可以称得上是【道】——【术】可以让你在IT行业赖以生存,而【道】则决定你未来在技术这条道路上可以走多远。

    边学边忘的窘境


    先自我介绍一下。

    我是一个两年工作经验的Android开发人员,就像很多同行一样,对于数据结构,算法,设计模式这些被奉为程序员必修的三门内功,几乎没有去系统性地学习过(曾经专业课的数据结构,如今也基本还给了老师)。

    你问我想不想当一个称职的程序员,当然!数据结构,算法以及设计模式不止一次的被我列入学习计划中,我认为这是有意义并且必须的,并且,我也尝试在闲暇之余去主动学习它们。

    但是很遗憾,至今为止,有关于数据结构和算法,我依然处于入门阶段,原因就是:

    我学会没多久,一直没机会用到,然后就忘了!

    如果您翻看过我之前的 相关博客 或者我 Github这个仓库,就能发现,我曾经关于数据结构和算法,都做出过尝试,但是遗憾的是,我并不能学以致用 ——它们匆匆而来,匆匆而去,就好像生命中的过客一样。

    至于设计模式,因为空闲时间学习的时间并不多,虽然我也经常通过博客或者书籍学习设计模式,但是结果依然没有太大的改变:过于抽象的概念,加上不经常使用,让我很快把这些概念忘得差不多了。

    我觉得这种学习方式效率不是很高,于是我决定换一种学习的方式——通过阅读Github上那些开源库的源码,学习其中的设计思想和理念。

    动机


    和大多数人一样,我只是在编程行业众多平凡的开发者中的一员,在我职业生涯的伊始,我没有接触过技术大牛, 但是阅读源码可以让我零距离碰撞全球行业最顶尖工程师们的思想,我认为对我而言这是一种效果不错的学习方式,让我受益匪浅。

    事实上,在要写这篇博客的时候,我依然忐忑不安,我担心一篇文章如果写的不够好,会给读者带来误导。

    我最终鼓起勇气写这篇文章的目的是:我想通过分享个人对于设计模式的理解,以及自己的学习方式和所得,这种学习方式可能并非适用于所有人,但是它至少能给予需要的人一个参考

    设计模式的分类


    我们先看设计模式的分类:

    范围创建型结构型行为型
    Factory Method(工厂方法)Adapter(类) (适配器)Interpreter(解释器)
    Template Method(模版方法)
    对象Abstract Factory(抽象工厂)
    Builder(建造者)
    Prototype(原型)
    Singleton(单例)
    Bridge(桥接)
    Composite(组合)
    Decorator(装饰者)
    Façade(外观)
    Flyweight(享元)
    Proxy(代理)
    Chain of Responsibility(职责链)
    Command(命令)
    Iterator(迭代器)
    Mediator(中介者)
    Memento(备忘录)
    Observer(观察者)
    State(状体)
    Strategy(策略)
    Visitor(访问者)

    这是我从 这篇文章 中找到的对设计模式的归纳。

    同时,我们需要了解到,设计模式的6个基本原则(这里先列出来,接下来会参考案例一个个解释):

    • 1、单一职责原则(Single Responsibility Principle)
    • 2、里氏代换原则(Liskov Substitution Principle)
    • 3、依赖倒转原则(Dependence Inversion Principle)
    • 4、接口隔离原则(Interface Segregation Principle)
    • 5、迪米特法则,又称最少知道原则(Demeter Principle)
    • 6、开闭原则(Open Close Principle)

    在设计模式的学习过程中,这些设计模式并非是按照不同类型循序渐进讲解的,更多的场景是,多个不同类型的设计模式相互组合——最终展示出来的是一个完整的架构设计体系。这种设计模式复杂组合带来的好处是:高内聚,低耦合,这使得库本身的拓展非常简单,同时也非常便于单元测试。

    当然,对于通过源码,想一窥设计思想的学习者来说,额外的接口,以及可能随之额来额外的代码会需要更多的学习成本,对于最初的我来说,复杂的设计真的给我带来了很大的困扰,我试图去理解和反思这样设计的好处——它的确花费了我更多的时间,但是更让我受益匪浅。

    最初的收获——创建型模式


    在Android学习的过程中,我最先接触到的就是创建型模式,所谓创建型模式,自然与对象的创建有关。

    实际上,不谈源码,实际开发中,我们也遇到了很多创建型模式的体现,最常见的当属单例模式建造者模式(Builder)

    1.“最简单”的设计模式

    我们以单例模式为例,他的定义是:

    “一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

    相信大家对这个单例模式并不陌生,它被称为 “设计模式中最简单的形式之一”,它很简单,并且易于理解,开发者总能遇到需要持有唯一对象的业务需求。

    以Android开发为例,经常需要在某个类中,使用到Application对象,它本身是唯一的,因此我们只需要通过一个类持有它的静态引用,然后通过静态方法获取就可以了。

    另外的一种需求是,某个类的对象会占用很大的内存,我们也没有必要对这个类实例化两次,这样,保持其对象的类单例,能够省下更多的性能空间,比如Android的数据库db的引用。

    实际上,单例模式的细分下来,有很多种实现方式,比如众所周知的懒汉式饿汉式Double CheckLock静态内部类枚举,这些不同的单例实现方式,都有各自的优缺点(比如是否线程安全),也对应着不同的适用场景,这也正是单例模式作为看起来“最简单”同时也是面试中的重点考察项目的原因。

    这些不同的实现方式,百度上讲解的非常详细,本文不赘述。

    我们需要理解的是,我们什么时候使用单例模式

    对于系统中的某些类来说,只有一个实例很重要,比如上述的Application,这很好理解,实际上,在开发过程中,我们更需要关注一些细节的实现。

    比如对Gson的单例。

    实际开发中,调用Gson对象进行转换的地方非常多,如果在调用的地方每次new Gson的话,是影响性能的。

    Gson本身是线程安全的,它可以被多个线程同时使用,因此,我更倾向于通过下面的方式获取Gson的实例:

    public class Gsons {
    
        private static class Holder {
            private static final Gson INSTANCE = new Gson();
        }
    
        public static Gson getInstance() {
            return Holder.INSTANCE;
        }
    }

    不仅是Gson, 除此之外还有比如网络请求的相关管理类(Retrofit对象,ServiceManager等),Android系统提供的各种XXXManager(NotificationManager)等等,这些通过单例的方式去管理它,能够让你业务设计的更加严谨。

    2.Builder的链式调用

    建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。

    Android开发者一定很熟悉它,因为我们创建AlertDialog的时候,链式调用的API实在是赏心悦目:

    new AlertDialog
       .Builder(this)
       .setTitle("标题")
       .setMessage("内容")
       .setNegativeButton("取消", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
                //...
           }
       })
       .setPositiveButton("确定", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
                //....
           }
       })
       .create()
       .show();

    此外,稍微细心的同学会发现,其实JDK中,StringBuilder和StringBuffer的源码中的append()方法也是Builder模式的体现:

    public StringBuilder append(String str) {
            super.append(str);  // 调用基类的append方法
            return this;
    }
    
    // 基类的append方法
    public AbstractStringBuilder append(String str) {
           if (str == null) str = "null";
           int len = str.length();
           ensureCapacityInternal(count + len);
           str.getChars(0, len, value, count);
           count += len;
           return this; // 返回构建对象
    }

    除了赏心悦目的代码之外,我更关注Builder模式的使用场景:

    当我们面临着一个复杂对象的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

    很好,我把 这个学习网站 关于Builder模式的适用场景复制下了下来,我曾经在学习它的时候尝试去理解它的叙述,所得出的结论是 ——上文的定义非常严谨,但是我看不懂。

    我们参考AlertDialog,对于一个Dialog而言,它的基本构成是复杂的(有标题,内容,按钮及其对应的事件等等属性),但是在实际需求中,不同的界面,我们需要展示给用户的Dialog是不一样的(标题不一样,内容不一样,点击事件也不一样),这些各个部分都是在不断剧烈的变化,但是他们组合起来是相对稳定的(就是一个Dialog弹出展示在界面上)。

    在这种情况下,我们可以尝试使用Builder模式,和普通的构造器生成对象不同,如果没有需求,我们可以忽略配置某些属性——对于Dialog,我可以不去定义title,也可以不去定义取消按钮的点击事件,他们内部都有默认的处理;此外,对于API的设计来讲,Builder模式更利于去扩展新的功能或者属性。

    Builder模式在我们开发中非常常见,除上述案例之外,Android流行的图片加载库,以及Notification通知的实例化等等,都能看到Builder的身影。

    上文说到,Builder模式对于对象的创建提供了非常赏心悦目的API,我理解了Builder模式的思想和实现方式之后,便尝试给自己的一些工具类加一些这样的设计。

    很快,我遇到了一个问题,那就是——这样写太TM累了!

    3.避免过度设计

    关于过度设计的定义,请参考 什么是软件开发中的过度设计? 的解释,我认为讲解的非常风趣且易懂。

    从我个人的角度而言,我遇到了问题,我尝试给一些工具改为Builder实现,结果是,我添加了很多很多代码,但是效果平平。

    不仅如此,这样的设计给我的工具带来了更多的复杂度,本来一个构造器new一下能解决的问题,非要很多行代码链式配置,这种设计,做了还不如不做。

    这样的结果,让我对网络上一位前辈的总结非常赞同,那就是:

    设计模式的一个重要的作用是代码复用,最终的目的是提升效率。
    所以,一个模式是否适合或必要,只要看看它是否能减少我们的工作,提升我们的工作效率

    那么,如何避免过度设计,我的经验告诉我,写代码之前多思考,考虑不同实现方式所需的成本,保证代码的不断迭代和调整

    即使如此,在开发的过程中,过度设计仍然是难以避免的情况,只有依靠经验的积累和不断的总结思考,慢慢调整和丰富自己的个人经验了。

    4. 单一职责原则与依赖注入

    对于单例模式,我似乎也会遇到过度设计这种情况——每个对象的单例都需要再写一个类去封装,似乎也太麻烦了。

    实际上这并非过度设计,因为这种设计是必要的,它能够节省性能的开销,但是对象的创建和管理依然是对开发者一个不可小觑的工作量。

    此外,还需要考量的是,对于一个复杂的单例对象,它可能有很多的状态和依赖,这意味着,单例类的职责很有可能很,这在一定程度上违背了单一职责原则

    一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

    单一职责原则告诉我们:一个类不能太“累”! 一个类的职责越(这往往从构造器所需要的依赖就能体现出来),它被复用的可能性就越小。

    在了解了单例模式的优点和缺点后,我们可以有选择的使用单例模式,对于依赖过于复杂的对象的单例,我们更需要仔细考量。

    对于复杂的依赖管理,依赖注入库(比如Dagger)是一个可以考虑的解决方案(慎重),对于单例模式的实现,你只需要在Module中对应的依赖Provider上添加一个@Singleton注解,编译器会在编译期间为您自动生成对应的单例模式代码。

    不能否认,这个工具需要相对较高的学习成本,但是学会了依赖注入工具并理解了IOC(控制反转)DI(依赖注入)的思想之后,它将成为你开发过程中无往不胜的利器。

    5.开闭原则

    开闭原则:一个软件应对扩展开放、对修改关闭,用head first中的话说就是:代码应该如晚霞中 的莲花一样关闭(免于改变),如晨曦中的莲花一样开放(能够扩展).

    建造者模式(Builder)便是开闭原则的完全体现,它将对象的构建调用隔离开来,不同的使用者都可以通过自由的构建对象,然后使用它。

    6.小结

    创建型模式是最容易入门的,因为该类型的模式,更经常暴露在开发者面前,但是它们并不简单,我们除了知道这些模式的使用方式,更应该去思考什么时候用,用哪个,甚至是组合使用它们——它们有些互斥,有些也可以互补,这需要我们去研究更经典的一些代码,并自己作出尝试。

    不只是创建型,接下来的结构型和行为型的设计模式,本文也不会去一一阐述其目录下所有的设计模式。

    结构型模式


    1.定义

    首先阐述书中结构型模式的定义:

    结构型模式涉及到如何组合类和对象以获得更大的结构。结构型类模式采用继承机制来组合接口或实现。

    在学习之初,对我个人而言,阅读《设计模式:可复用面向对象软件的基础》 的内容宛如诵读天书,书中对每种设计模式都进行了详细的讲解,但是我看完之后,很快就忘掉了,亦或是对看起来非常相似的两种设计模式感到疑惑——书中的讲解细致入微,但是太抽象了。

    最终(也就是现在),我个人对于结构型模式的理解是,通过将不同类或对象的组合,采用继承或者组合接口,或者组合一些对象,以实现新的功能

    用一句话陈述,就是对不同职责的对象(以对象/抽象类/接口的形式)之间组合调度的实现方式。

    2.并非所有对象的组合都是结构型模式

    实际上,并非所有对对象的组合都属于结构型模式,构型模式的意义在于,对一些对象的组合,以实现新功能的方式—— 通过运行时,通过改变组合的关系,这种灵活性产生不同的效果,这种机制,普通的对象组合是不可能实现的。

    接下来我将通过阐述数种不同的结构型模式在实际开发中的应用,逐步加深对上文叙述的理解。

    3.RecyclerView:适配器模式

    RecyclerView是Android日常开发中实现列表的首选方案,站在我的角度来看,我还没想明白一个问题,RecyclerView是如何实现列表的?

    我可以回答说,通过实现RecyclerView.Adapter就能实现列表呀!

    事实上,是这样的,但是这引发了另外一个问题,Adapter和RecyclerView之间的关系是什么,为啥实现了Adapter就能实现RecyclerView呢?

    思考现实中的一个问题,我有一台笔记本电脑,我的屋子里也有一个电源,我如何给我的笔记本充电?

    不假思索,我们用笔记本的充电器连接电源和笔记本就行了,实际上,充电器更官方的叫法应该叫做电源适配器(Adapter)。对于笔记本电脑和电源来讲,它们并没有直接的关系,但是通过Adapter适配器,它们就能产生新的功能——电源给笔记本充电。

    RecyclerView和数据的展示也是一样,数据对象和RecyclerView并没有直接的关系,但是我如果想要将数据展示在RecyclerView上,通过给RecyclerView配置一个适配器(Adapter)以连接数据源,就可以了。

    现在我们来看Adapter模式的定义:

    使原本由于接口不兼容而不能一起工作的那些类可以一起工作。

    现在我们理解了适配器模式的应用场景,但是我想抛出一个问题:

    为啥我要实现一个Adapter,设计之初,为什么不能直接设置RecyclerView呢?

    比如说,我既然有了数据源,为什么设计之初,不能让RecyclerView通过这样直接配置呢:

    mRecyclerView.setDataAndShow(datas);

    我的理解是,如果把RecyclerView比喻为屋子里的电源插口,电源不知道它将要连接什么设备(同样,RecyclerView也不可能知道它要展示什么样的数据,怎么展示),而不同的设备的接口也可能不一样,但是只要为设备配置一个对应的适配器,两个不相关的接口就能一起工作。

    RecyclerView的设计者将实现对开发者隐藏,并通过Adapter对开发者暴露其接口,开发者通过配置数据源(设备)和对应的适配器(充电器),就能实现列表的展示(充电)。

    4.Retrofit:外观模式与动态代理

    说到迪米特法则(也叫最少知识原则),这个应该很好理解,就是降低各模块之间的耦合:

    迪米特法则:一个软件实体应当尽可能少地与其他实体发生作用。

    我的学习过程中,让我感受到设计模式的组合之美的第一个库就是Retrofit,对于网络请求,你只需要配置一个接口:

    public interface BlogService {
    
        @GET("blog/{id}")
        Call<ResponseBody> getBlog(@Path("id") int id);
    }
    
    // 使用方式
    // 1.初始化配置Retrofit对象
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://localhost:4567/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    // 2.实例化BlogService接口        
    BlogService service = retrofit.create(BlogService.class);

    Retrofit的源码中,通过组合,将各种设计模式应用在一起,构成了整个框架,保证了我们常说的高内聚,低耦合,堪称设计模式学习案例的典范,如下图(图片参考感谢这篇文章):

    在分析整个框架的时候,我们首先从API的使用方式入手,我们可以看到,在配置Retrofit的时候,库采用了外观模式作为Retrofit的门面。

    有朋友说了,在我看来,Retrofit的初始化,不应该是Builder模式吗,为什么你说它是外观模式呢?

    我们首先看一下《设计模式:可复用面向对象软件的基础》一书对于外观模式的定义:

    为子系统中的一组接口提供一个一致的界面,外观模式定义一个高层接口,这个接口使得这一子系统更容易使用。

    我的解读是,对于网络请求库的Retrofit,它内部有着很多不同的组件,包括数据的序列化,线程的调度,不同的适配器等,这一系列复杂的子系统,对于网络请求来讲,都是不可或缺的且关系复杂的,那么,通过将它们都交给Retrofit对象配置调度(当然,Retrofit对象的创建是通过Builder模式实现的),对于API的调用者来说,使用配置起来简单方便,这符合外观模式 的定义。

    简单理解了外观模式的思想,接下来我们来看一下动态代理,对于最初接触Retrofit的我来说,我最难以理解的是我只配置了一个接口,Retrofit是如何帮我把Service对象创建出来的呢?

    // 2.实例化BlogService接口        
    BlogService service = retrofit.create(BlogService.class);

    实际上,并没有BlogService这个对象的创建,service只不过是在jvm运行时动态生成的一个proxy对象,这个proxy对象的意义是:

    为其他对象提供一种代理以控制对这个对象的访问。

    我想通过BlogService进行网络请求,Retrofit就会通过动态代理实现一个proxy对象代理BlogService的行为,当我调用它的某个方法请求网络时,实际上是这个proxy对象通过解析你的注解方法的参数,通过一系列的逻辑包装成一个网络请求的OkHttpCall对象,并请求网络。

    现在我明白了,怪不得我无论怎么给Service的接口和方法命名,Retrofit都会动态生成代理对象并在调用其方法时进行解析,对于复杂多变的网络请求来讲,这种实现的方式非常合适。

    5.里氏替换原则

    在优秀的源码中,我们经常可以看到,很多功能的实现,都是依赖其接口进行的,这里我们首先要理解面向对象中最重要的基本原则之一里氏替换原则

    任何基类可以出现的地方,子类一定可以出现。

    里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

    向上转型是Java的基础,我们经常也用到,实际上,在进行设计的时候,尽量从抽象类继承,而不是从具体类继承。同时,保证在软件系统中,把父类都替换成它的子类,程序的行为没有变化,就足够了。

    6.小结

    通过上述案例,我们简单理解了几种结构型设计模式的概念和思想,总结一下:

    在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。所以也有多种结构型模式可供开发人员选择使用。

    提高类之间的协作效率——行为型模式


    1.定义

    我们先看书中对行为型模式比较严谨的定义:

    行为模式涉及到算法和对象间职责的分配,行为模式不仅描述对象或类的模式,还描述它们之间的通信模式。这些模式刻划了在运行时难以跟踪的复杂的控制流,将你的注意力从控制流转移到对象间的联系方式上来。

    依然是有点难以理解,我们先举两个例子:

    2.OkHttp:Intercepter和职责链模式

    Okhttp 中, Intercepter就是典型的职责链模式的体现.它可以设置任意数量的Intercepter来对网络请求及其响应做任何中间处理——设置缓存, Https的证书验证, 统一对请求加密/防串改, 打印自定义Log, 过滤请求等。

    new OkHttpClient.Builder()
                  .addNetworkInterceptor(interceptor1)
                  .addNetworkInterceptor(interceptor2)
                  .addNetworkInterceptor(interceptor3)

    职责链模式的定义为:

    让多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将他们连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

    以现实为例,职责链模式之一就是网络连接,七层或五层的网络连接模型如下:

    • 网络请求发出,经过应用层->传输层->网络层->连接层->物理层

    • 收到响应后,物理层->连接层->网络层->传输层->应用层

    在请求经过各层时,由每层轮流处理.每层都可以对请求或响应进行处理.并可以中断链接,以自身为终点返回响应。

    3.RxJava:观察者模式

    Android开发中,点击事件的监听是很经典观察者模式的体现:

    button.setOnClickListener(v -> {
        // do something
    })

    对设置OnClickListener来说,View是被观察者,OnClickListener是观察者,两者通过setOnClickListener()方法达成注册(订阅)关系。订阅之后,当用户点击按钮,View就会将点击事件发送给已经注册的 OnClickListener。

    同样,对于可以和Retrofit配套的RxJava来讲,它是也通过观察者模式来实现的。

    // 被观察者
    Observable observable = Observable
                              .just("Hello", "Hi", "Aloha")
    
    // 观察者
    Observer<String> observer = new Observer<String>() {
        @Override
        public void onNext(String s) {
            Log.d(tag, "Item: " + s);
        }
    
        @Override
        public void onCompleted() {
            Log.d(tag, "Completed!");
        }
    
        @Override
        public void onError(Throwable e) {
            Log.d(tag, "Error!");
        }
    };
    
    // 执行订阅关系
    observable.subscribe(observer);

    RxJava强大的异步处理,将数据的创建接收分成了两部分,对于观察者来说,它不关心数据什么时候发射的,怎么发射的,它只关心,当观察到到最新数据时,怎样进行对应的处理。

    我们知道了观察者模式的这种方式,我们更需要去深入思考对于观察者模式使用前后,对我们代码设计系统的影响——它的好处是什么?

    最直接的好处是,被观察者并不知道观察者的详细实现

    就像我刚才所说的,被观察者只负责发射事件,对于事件如何处理,它并不关心,这意味着被观察者观察者之间并不是紧密耦合的,它们可以处于一个系统中的不同抽象层次。

    不同抽象层次这句话本身就有点抽象,我们以Button的点击事件为例,对于Button来讲,它是一个库的工具,它应该属于项目中底层组件,而对于我们某个Activity的某个点击事件来讲,它是属于靠顶部业务层的代码,可以说,Button和点击事件是不在一个抽象层次较低层次的Button可以将点击事件发送给较高层次的事件监听器并通知它。

    而如果不采用这种方式,观察者和被观察者就必须混在一起,这样对象就会横贯项目的2个层次(违反了层次性),或者必须放在这两层中的某一层中(可能会损害层次抽象)。

    底层组件按钮被点击后行为,抽象出来交给较高层级去实现,了解了这种方式的好处,依赖倒置原则就不难理解了。

    4.依赖倒置原则

    现在我们来了解一下依赖倒置原则

    抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而非针对实现编程。

    它的原则是:

    • 1.高层模块不应该依赖于低层模块,两个都应该依赖于抽象。
    • 2.抽象不应该依赖细节,细节应该依赖于抽象。

    在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

    了解了依赖倒置原则,我们再接再厉,学习最后一个设计模式的基本原则:

    5.接口隔离原则

    接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。

    这个应该是最好理解的原则了,它的意义就是:使用多个专门的接口比使用单一的总接口要好

    这很好理解,对于鸟的实现(Bird),我们可以定义两个功能接口,分别是Fly和Eat,我们可以让Bird分别实现这两个接口——如果我们还有一个Dog,那么对于Eat接口,可以复用,但是如果只有一个接口(包含Fly和Eat两个功能),对于Dog来说,它是不会飞(Fly)的,那么就需要针对Dog再声明一个新的接口,这是没有必要的设计。

    6.小结

    在对象的结构和对象的创建问题都解决了之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协作效率就会提高。

    现在我们再看上文中对行为型模式比较严谨的定义,相信大家能够理解一些了:

    行为模式涉及到算法和对象间职责的分配,行为模式不仅描述对象或类的模式,还描述它们之间的通信模式。这些模式刻划了在运行时难以跟踪的复杂的控制流,将你的注意力从控制流转移到对象间的联系方式上来。

    喘口气


    关于设计模式相关的讲解内容,到此基本就告一段落了。

    等等…

    我一个设计模式都没学会,你TM告诉我你讲完了?

    一无所获?

    本文并没有去通过代码简单描述各个设计模式的实现方式,于我而言毫无意义,设计思想是通过不断思考,理解并在亲身尝试中学会的,短时间快速大量阅读学习的方式效果甚微,即使学会了,如何将sample中的设计思想,转换为实际产品中复杂的业务设计,这也是一个非常大的难题。

    在这里,我引用《倚天屠龙记》中我最喜欢的经典片段, 就是张三丰在武当山当着敌人的面教张无忌太极剑那段。

    “只听张三丰问道:‘孩儿,你看清楚了没有?’张无忌道:‘看清楚了。’张三丰道: ‘都记得了没有?’张无忌道:‘已忘记了一小半。’张三丰道:‘好,那也难为了你。你自己去想想罢。’张无忌低头默想。过了一会,张三丰问道:‘现下怎样了?’张无忌道: ‘已忘记了一大半。’

     周颠失声叫道:‘糟糕!越来越忘记得多了。张真人,你这路剑法很是深奥,看一遍怎能记得?请你再使一遍给我们教主瞧瞧罢。’

     张三丰微笑道:‘好,我再使一遍。’提剑出招,演将起来。众人只看了数招,心下大奇,原来第二次所使,和第一次使的竟然没一招相同。周颠叫道:‘糟糕,糟糕!这可更加叫人胡涂啦。’张三丰画剑成圈,问道:‘孩儿,怎样啦?’张无忌道:‘还有三招没忘记。’张三丰点点头,收剑归座。

     张无忌在殿上缓缓踱了一个圈子,沉思半晌,又缓缓踱了半个圈子,抬起头来,满脸喜色,叫道:‘这我可全忘了,忘得干干净净的了。’张三丰道:‘不坏不坏!忘得真快,你这就请八臂神剑指教罢!’”

    总结


    关于设计模式,我的理解是,不要拘泥于其概念,只有深刻理解了其设计的思想,理解之后,亲自去尝试使用它,在使用的过程中加深对这种思想的理解,我想比通过书籍或者博客一个一个的去学,效果要更好。

    我学习它们的方式是,学习一些优秀开源库的源码,思考为什么这里使用这些设计模式,之后再参考《设计模式》一书的相关概念,最后自己去尝试并加深理解。

    于我而言,这种方式的短板在于刚开始的时候,可能需要更多的时间去学习,很多库的源码在初接触时,并非容易理解,但是好处是,当学会之后,这种思想就很难再从你的记忆中跑掉了,而且,在写代码时,会下意识尝试使用这些模式(当然,更多情况是打开2个窗口,一边参考源码,一边学习将其融入到自己的代码中)。

    设计模式相对于分类和概念正如太极拳(剑),它更是一种思想,一种应对变化的解决思想——我不认为本文自己的学习方式和心得,能够适合每一个正在阅读本文的读者,但是如果本文对您对技术成长的道路上有一些帮助,对我而言这就是值得的。

    参考


    1.菜鸟教程——设计模式:
    http://www.runoob.com/design-pattern/design-pattern-tutorial.html

    2.《设计模式:可复用面向对象软件的基础》
    伽玛等著;李英军等译,机械工业出版社,2015年12月第一版37次印刷

    3.Retrofit分析-漂亮的解耦套路:
    https://blog.piasy.com/2016/06/25/Understand-Retrofit/

    4.创建型模式、结构型模式和行为型模式之间的关系
    https://blog.csdn.net/qq_34583891/article/details/70853637

    展开全文
  • Java设计模式

    千次阅读 多人点赞 2019-09-03 23:20:31
    Java设计模式 1.工厂模式 工厂模式一般分为简单工厂、工厂、抽象工厂3钟情况,属于创建型设计模式。 2.生成器模式 3.观察者模式 4.桥接模式 5.代理模式 6.状态模式 7.访问者模式 ...

    Java设计模式

    1.工厂模式

    2.生成器模式

    3.观察者模式

    4.桥接模式

    5.代理模式

    6.状态模式

    7.访问者模式

    8.命令模式

    9.装饰器模式

    10.组合模式

    1.工厂模式

    工厂模式一般分为简单工厂、工厂、抽象工厂3种情况,属于创建型设计模式。

    简单工厂(静态工厂)

    //定义小汽车接口:ICar.java
    public interface ICar{
      //由于工厂模式仅关系对象的创建,为说明方便,无需定义方法
    }
    
    //下面定义高、中、低档具体的汽车
    //高档小汽车:TopCar.java
    public class TopCar implements ICar{
    }
    //中档小汽车:MidCar.java
    public class MidCar implements ICar {
    }
    //低档小汽车:LowCar.java
    public class LowCar implements ICar {
    }
    
    //简单工厂:CarSimpleFactory.java
    public class CarSimpleFactory {
        public static final String TOPTYPE = "toptype";
        public static final String MIDTYPE = "midtype";
        public static final String LOWTYPE = "lowtype";
        public static ICar create(String mark){
        ICar obj = null;
        if(mark.equals(TOPTYPE)){ //如果是高档类型
          obj = new TopCar();  //则创建高档车对象
        }
        else if(mark.equals(MIDTYPE)){
        obj = new MidCar();
      }
        else if(mark.equals(LOWTYPE)){
        obj = new LowCar();
      }
        return obj;    //返回选择的对象
      }
    }
    
    //测试程序:CarTest.java
    public class CarTest {
      public static void main(String[] args) {
      //从工厂中创建对象
        ICar obj = CarSimpleFactory.create("toptype");
      }
    }
    

    工厂

    //定义小汽车接口:ICar.java
    public interface ICar {
    //由于工厂模式仅关系对象的创建,为说明方便,无需定义方法
    }
    //定义高、中、低档具体的小汽车
    //高档小汽车:TopCar.java
    public class TopCar implements ICar {
    }
    //中档小汽车:MidCar.java
    public class MidCar implements ICar {
    }
    //低档小汽车:LowCar.java
    public class LowCar implements ICar {
    }
    //定义抽象工厂:AbstractFactory.java
    public abstract class AbstractFactory {
    public abstract ICar create();
    }
    //定义高档小汽车工厂:TopFactory.java
    public class TopFactory extends AbstractFactory {
    public ICar create() {
        return new TopCar(); //高档工厂生成高档小汽车对象
      }
    }
    //定义中档小汽车工厂:MidFactory.java
    public class MidFactory extends AbstractFactory {
    public ICar create() {
        return new MidCar(); //中档工厂生成中档小汽车对象
      }
    }
    //定义低档小汽车工厂:LowFactory.java
    public class LowFactory extends AbstractFactory {
    public ICar create() {
        return new LowCar(); //低档工厂生成低档小汽车对象
      }
    }
    //测试类:CarTest.java
    public class CarTest {
    public static void main(String []args){
        AbstractFactory obj = new TopFactory();//多态创建高档工厂
        ICar car = obj.create();    //获得高档工厂中的小汽车对象
      }
    }
    

    抽象工厂

    //小汽车接口
    public interface ICar { }
    public class TopCar implements ICar { }
    public class MidCar implements ICar { }
    public class LowCar implements ICar { }
    
    //定义公共汽车接口、高、中、低档公共汽车类
    public interface IBus { }
    public class UpBus implements IBus { }
    public class MidBus implements IBus { }
    public class DnBus implements IBus { }
    
    //定义抽象工厂:AbstractFactory.java
    public absttract class AbstractFactory {
    public abstract ICar createCar(); //产生小汽车对象
    public abstract IBus createBus(); //产生公共汽车对象
    }
    
    //定义高档工厂:TopFactory.java
    public class TopFactory extends AbstractFactory {
      public ICar createCar() {
        return new TopCar();  //高档工厂生成高档小汽车对象
      }
      public IBus createBus() {
        return new UpBus();  //高档工厂生成高档公共汽车对象
      }
    }
    
    //定义中档工厂:MidFactory.java
    public class MidFactory extends AbstractFactory {
      public ICar createCar() {
        return new MidCar();  //中档工厂生成中档小汽车对象
      }
      public IBus createBus() {
        return new MidBus();  //中档工厂生成中档公共汽车对象
      }
    }
    //定义低档工厂:LowFactory.java
    public class LowFactory extends AbstractFactory {
      public ICar createCar() {
        return new LowCar();  //低档工厂生成中档小汽车对象
      }
      public IBus createBus() {
        return new DnBus();  //低档工厂生成中档公共汽车对象
      }
    }
    

    2.生成器模式

    生成器模式也称为建造者模式。生成器模式的意图在于将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。在软件设计中,有时候面临着一个非常复杂的对象的创建工作。这个复杂的对象通常可以分成几个较小的部分,由各个子对象组合出这个复杂对象的过程相对来说比较稳定,但是子对象的创建过程各不相同并且可能面临变化。根据OOD中的OCP原则,应该对这些子对象的创建过程进行变化封装。

    生成器思路是产品类与创建产品的类相分离。产品类仅1个,创建产品的类有n个。

    生成器设计模式涉及4个关键角色:产品(Product)、抽象生成器(IBuild)、具体生成器(Builder)、指挥者(Director)。
    在这里插入图片描述

    (1)定义1个产品类。
    public class Unit1{……}
    public class Unit2{……}
    public class Unit3{……}
    public class Product {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;
    }
    由于不在该类完成Product类对象的创建,所以无需显示定义构造方法。
    
    (2)定义n个生成器Build类。
    根据语义,生成器是用来生成Product对象的,因此一般来说,Product是生成器类的一个成员变量;
    根据语义,每创建一个Product对象,本质上都需要先创建Unit1,Unit2,…, UnitN,再把它们组合成所需的Product对象,
    因此需要n个createUnit()方法及一个组合方法composite();由于createUnit()及composite()是共性,
    因此可定义共同的生成器类接口, n个生成器类均从此接口派生即可。代码如下。
    //定义生成器类接口IBuild
    public interface IBuild {
    public void createUnit1();
    public void createUnit2();
    public void createUnit3();
    public Product composite();    //返回值是Product对象
    }
    //定义3个生成器类
    public class BuildProduct implements IBuild { //生成第一种Product
    Product p = new Product();     //Product是成员变量
    public void createUnit1() {
    //p.u1= ...       //创建Unit1
    }
    public void createUnit2() {
    //p.u2 = ...       //创建Unit2
    }
    public void createUnit3() {
    //p.u3 =  //创建Unit3
    }
    public Product composite() {
    //...   //关联Unit,Unit2,Unit3
    return p;  //返回Product对象p
    }
    }
    public class BuildProduct2 implements IBuild {  //生成第2种Product
    Product p = new Product();//Product是成员变量
    public void createUnit() {/*p.u = ...... */} //创建Unit
    public void createUnit2(){/*p.u2 = ...... */} //创建Unit2
    public void createUnit3(){/*p.u3 = ...... */} //创建Unit3
    public Product composite() {
    //......    //关联Unit1,Unit2,Unit3
    return p;   //返回Product对象p
    }
    }
    public class BuildProduct3 implements IBuild {  //生成第3种Product
    Product p = new Product();//Product是成员变量
    public void createUnit1() {/*p.u1 = ...... */} //创建Unit1
    public void createUnit2(){/*p.u2 = ...... */} //创建Unit2
    public void createUnit3(){/*p.u3 = ...... */} //创建Unit3
    public Product composite() {
    //......  //关联Unit1,Unit2,Unit3
    return p;  //返回Product对象p
    }
    }
    通过上述代码可知,若需求分析发生变化,只需增加或删除相应的生成器类即可,无需修改已有的类代码。
    (3)定义1个统一调度类,也叫指挥者(Director)类,是对生成器接口IBuild的封装。该类及简单的测试代码如下。
    public class Director {
    private IBuild build;
    public Director(IBuild build){
    this.build = build;
    }
    public Product build(){
    build.createUnit1();
    build.createUnit2();
    build.createUnit3();
    return build.composite();
    }
    public static void main(String []args){
    IBuild build = new BuildProduct();
    Director direct = new Director(build);
    Product p = direct.build();
    }
    }
    

    3.观察者模式

    观察者设计模式适合解决多种对象跟踪一个对象数据变化的程序结构问题,有一个称作“主题”的对象和若干个称作“观察者”的对象。有一个主题数据——温度,3个观察者—温度日志、温度曲线、温度报警。因此观察者设计模式涉及两种角色:主题和观察者。
    观察者设计模式可以从以下递推中得出一些重要结论。
    ● 主题要知道有哪些观察者对其进行监测,因此主题类中一定有一个集合类成员变量,包含了观察者的对象集合。
    ● 既然包含了观察者的对象集合,那么,观察者一定是多态的,有共同的父类接口。
    ● 主题完成的主要功能是:可以添加观察者,可以撤销观察者,可以向观察者发消息,引起观察者响应。这三个功能是固定的,因此主题类可以从固定的接口派生。
    因此,编制观察者设计模式,要完成以下功能类的编制。
    ● 主题ISubject接口定义。
    ● 主题类编制。
    ● 观察者接口IObserver定义。
    ● 观察者类实现。
    在这里插入图片描述

    (1)观察者接口IObserver。
    
        public interface IObserver {
            public void refresh(String data);
        }
        
    (2)主题接口ISubject。
    
        public interface ISubject {
            public void register(IObserver obs);       //注册观察者
            public void unregister(IObserver obs);     //撤销观察者
            public void notifyObservers();             //通知所有观察者
        }
        
    (3)主题实现类Subject。
    
        public class Subject implements ISubject {
            private Vector<IObserver> vec = new Vector();  //观察者维护向量
            private String data;                           //主题中心数据
    
            public String getData() {
                return data;
            }
            public void setData(String data) {              //主题注册(添加)
                this.data = data;
            }
            public void register(IObserver obs) {           //主题注册(添加)观察者
             vec.add(obs);
            }
    
            public void unregister(IObserver obs) {         //主题撤销(删除)观察者
                if(vec.contains(obs))
                    vec.remove(obs);
            }
            public void notifyObservers(){             //主题通知所有观察者进行数据响应
                for(int i=0; i<vec.size(); i++){
                    IObserver obs = vec.get(i);
                    obs.refresh(data);
                }
            }
        }
        
        主题实现类Subject是观察者设计模式中最重要的一个类,包含了观察者对象的维护向量vec以及主题中心数据data变量与具体观察者对象的关联
        方法(通过nitofyObservers())。也就是说,从此类出发,可以更深刻地理解ISubject为什么定义了3个方法、IObserver接口为什么定义了1个方法。
        
    (4)一个具体观察者类Observer。
    
        public class Observer implements IObserver {
            public void refresh(String data) {
                System.out.println("I have received the data:" +data);
            }
        }
        
    (5)一个简单的测试类Test。
    
        public class Test {
            public static void main(String[] args) {
                IObserver obs = new Observer();    //定义观察者对象
                Subject subject = new Subject();
                //定义主题对象
                subject.register(obs);             //主题添加观察者
                subject.setData("hello");          //主题中心数据发生变动
                subject.notifyObservers();         //通知所有观察者进行数据响应
            }
        }
        
    该段代码的含义是:当主题中心数据变化(通过setData方法)后,主题类subject要调用notifyObservers()方法,
    通知所有观察者对象接收数据并进行数据响应。
    

    4.桥接模式

    桥接模式是关于怎样将抽象部分与它的实现部分分离,使它们都可以独立地变化的成熟模式。
    在这里插入图片描述

    (1)定义邮寄接口IPost。
    
        public interface IPost{   //邮局
            public void post();   //发送功能
        }
        
    (2)两个具体邮寄类SimplePost、MarkPost。
    
        //平信邮寄类SimplePost
        class SimplePost implements IPost{     //平信
            public void post(){                //发送
                System.out.println("This is Simple post");
            }
        }
        //挂号邮寄类
        class MarkPost implements IPost{       //挂号
            public void post(){                //发送
                System.out.println("This is Mark post");
            }
        }
        
      经过(1)、(2)的论述,完成了语义的前半部分定义:邮局有发送功能;发送有两种方式,平邮和挂号。
      
    (3)抽象事物类AbstractThing。
    
        abstract class AbstractThing{ //抽象事物
    
            private IPost obj;         //有抽象发送功能
            public AbstractThing(IPost obj){
                this.obj = obj;
            }
            public void post(){
                obj.post();
            }
        }
        
    该类是桥接模式的核心。分析语义“信件和包裹共享平邮与挂号功能”:信件、包裹是两个不同的事物,它们有共享的功能,
    也一定有相异的功能。共享的功能一定能封装到一个类中,又由于该类不能代表一个具体的事物,所以把它定义成abstract类是恰当的。
    该类共享的是多态成员obj,是IPost类型的,是抽象的、泛指的,用一条语句表明了事物共享平邮和发送功能。
    
    (4)具体事物类Letter、Parcel。
    
        //信件类Letter
        class Letter extends AbstractThing{
            public Letter(IPost obj){
                super(obj);
            }
            //其他独有变量和方法
        }
        //包裹类Parcel
        class Parcel extends AbstractThing{
            public Parcel(IPost obj){
                super(obj);
            }
            //其他独有变量和方法
        }
        
        //编制一个简单的测试类
        public class Test {
            public static void main(String[] args) {
                IPost p = new SimplePost();
    
                Letter letter = new Letter(p);
                letter.post();
            }
        }
        
    第一种情况:若增加了新的事物,则只需从Abstract派生一个类即可,其他无需改变。
    
        class NewThing extends AbstractThing{
            public NewThing(IPost obj){
                super(obj);
            }
            //其他独有变量和方法
        }
        
    第二种情况:若增加了新的邮寄类别,比如特快专递,则只需从IPost接口派生一个类即可,其他无需改变。
    
        class EMSPost implements IPost{        //特快专递
        public void post(){                //发送
                System.out.println("This is EMS post");
            }
        }
    

    5.代理模式

    代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。代理模式则是一种可以很好实现客户对象与代理对象分离的策略。

    代理模式的定义如下:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的英文叫作Proxy或Surrogate,它是一种对象结构型模式。其抽象UML图如图所示
    在这里插入图片描述
    代理模式包含如下角色
    ● ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。
    ● RealSubject:真实主题角色,是实现抽象主题接口的类。
    ● Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。以买电视为例,其代码如下。
    (1)定义抽象主题——买电视。

    interface ITV{
            public void buyTV();
        }
    

    (2)定义实际主题——买电视过程。

    class Buyer implements ITV{
        public void buyTV(){
            System.out.println("I have bought the TV by buyer proxy");
        }
    }
    

    真正的付费是由购买者完成的。
    (3)定义代理。

    class BuyerProxy implements ITV{
        private Buyer buyer;
        public BuyerProxy(Buyer buyer){
            this.buyer = buyer;
        }
        public void buyTV(){
            preProcess();
            buyer.buyTV();
            postProcess();
        }
        public void preProcess(){
            //询问客户需要电视类型、价位等信息
        }
        public void postProcess(){
            //负责把电视送到客户家
        }
    }
    

    电视代理商BuyerProxy与购买者Buyer都实现了相同的接口ITV,是对Buyer对象的进一步封装。着重理解buyTV()方法:首先代理商要通过preProcess()询问客户买电视的类型、价位等信息,然后购买者通过buyer.buyTV()自己付费完成电视购买,最后代理商通过postProcess()协商具体的送货服务、产品三包等。

    代理模式最突出的特点是:代理角色与实际主题角色有相同的父类接口。常用的代理方式有4类:虚拟代理、远程代理、计数代理、动态代理

    虚拟代理
    虚拟代理的关键思想是:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。当用户请求一个“大”对象时,虚拟代理在该对象真正被创建出来之前扮演着替身的角色;当该对象被创建出来之后,虚拟代理就将用户的请求直接委托给该对象。

    远程代理
    远程代理的含义是:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以在同一台主机中,也可在另一台主机中。也就是说,远程对象驻留于服务器上,客户机请求调用远程对象调用相应方法,执行完毕后,结果由服务器返回给客户端。
    在这里插入图片描述
    计数代理
    当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或计数的额外功能时,就可以使用计数代理模式。计数代理模式并不是把这些额外操作的代码直接添加到源服务中,而是把它们封装成一个单独的对象,这就是计数代理。

    动态代理
    对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。
    静态代理模式简图
    但是,也常存在这样的情况,有n个主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同,需要编制如图所示的程序框架。
    [动态代理模式简图]
    也就是说,多个主题类对应一个代理类,共享“前处理、后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点。实现动态代理的关键技术是反射。

    6.状态模式

    状态模式为研究各种状态以及状态间相互转化的实现方式提出了一种较好的设计思路。

    ● 状态类有共同的父接口(或抽象类), n个不同的状态实现类。
    ● 事物类中包含状态类父接口成员变量声明,用以反映语义“事物有n个状态”。
    ● 事物类中一定有方法选择分支,判断事物当前处于何种状态。

    状态模式必须完成如下内容的编制:
    ● State:状态接口,封装特定状态所对应的行为。
    ● ConcreteState:具体实现状态处理的类。
    ● Context:事物类,也称上下文类,通常用来定义多态状态接口,同时维护一个用来具体处理当前状态的示例对象。

    状态模式的UML抽象类图如图所示
    在这里插入图片描述
    状态模式的具体抽象代码如下。
    (1)定义状态抽象接口IState。

    interface IState{
        public void goState();
    }
    

    (2)定义状态实现类。

    class ConcreteStateA implements IState{//定义状态A类
        public void goState(){
            System.out.println("This is ConcreteStateA");
        }
    }
    class ConcreteStateB implements IState{//定义状态B类
        public void goState(){
            System.out.println("This is ConcreteStateB");
        }
    }
    

    (3)定义状态上下文维护类Context。

    class Context{            //上下文有n种状态
        private IState state;
        public void setState(IState state){
            this.state = state;
        }
        public void manage(){
            //此处代码根据条件选择某种状态
            state.goState(); //执行某种状态功能
        }
    }
    

    Context类是实现状态模式的关键,本部分仅列出了状态模式的基本代码

    7.访问者模式

    访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式,这就是访问者模式的模式动机。

    访问者模式抽象类图
    在这里插入图片描述
    访问者模式主要涉及以下四种角色:
    ● IElement:抽象的事物元素功能接口,定义了固定功能方法及可变功能方法接口。
    ● Element:具体功能的实现类。
    ● IVisitor:访问者接口,为所有访问者对象声明一个visit方法,用来代表为对象结构添加的功能,原则上可以代表任意的功能。
    ● Visitor:具体访问者实现类,实现要真正被添加到对象结构中的功能。

    考虑这样一个应用:已知三点坐标,编写功能类,求该三角形的面积和周长。

    如果采用访问者模式,应当这样思考:目前已确定的需求分析是求面积和周长功能,但有可能将来求三角形的重心、垂心坐标,内切、外界圆的半径等,因此,在设计时必须考虑如何屏蔽这些不确定情况。具体代码如下。

    1.定义抽象需求分析接口IShape

    interface IShape{
        float getArea();             //明确的需求分析
        float getLength();           //明确的需求分析
        Object accept(IVisitor v);   //可扩展的需求分析
    }
    

    着重理解可扩展的需求分析方法accept(),它在形式上仅是一个方法,但是按访问者模式而言,它却可以表示将来可以求重心、垂心坐标等功能,是一对多的关系,因此IVisitor一般来说是接口或抽象类,“多”项功能一定是由IVisitor的子类来实现的。那么为什么返回值是Object类型呢?可以这样理解,例如重心坐标由两个浮点数表示,外接圆半径由一个浮点数表示,为了屏蔽返回值差异,返回值定义成Object,表明可以返回任意对象类型。

    2.定义具体功能实现类Triangle

    class Triangle implements IShape{
        float x1, y1, x2, y2, x3, y3;           //三角形三点坐标
        public Triangle(float x1, float y1, float x2, float y2, float x3, float y3){
    
            this.x1=x1; this.y1=y1;
            this.x2=x2; this.y2=y2;
            this.x3=x3; this.y3=y3;
        }
        public float getDist(float u1, float v1, float u2, float v2){   //求任意两点距离
            return (float)Math.sqrt((u1-u2)*(u1-u2)+(v1-v2)*(v1-v2));
        }
        public float getArea(){            //固定需求分析求面积
            float a = getDist(x1, y1, x2, y2);
            float b = getDist(x1, y1, x3, y3);
            float c = getDist(x2, y2, x3, y3);
            float s = (a+b+c)/2;
            return (float)Math.sqrt(s*(s-a)*(s-b)*(s-c)); //海伦公式求面积
        }
        public float getLength(){          //固定需求分析求周长
            float a = getDist(x1, y1, x2, y2);
            float b = getDist(x1, y1, x3, y3);
            float c = getDist(x2, y2, x3, y3);
            return a+b+c;
        }
        public Object accept(IVisitor v){  //可扩展需求分析
            return v.visit(this);
        }
    }
    

    着重理解accept()方法,可以看出IVisitor接口中一定定义了多态方法visit(),那为什么把this引用传过去呢?可以这样理解:例如求三角形重心坐标,它的功能一定是在IVisitor的子类实现的,那么该子类一定得知道三角形的三个顶点坐标,因此把this引用传过去,相当于IVisitor的子类可访问Triangle类的成员变量,编制求重心坐标就容易了。

    3.定义访问者接口IVisitor

    interface IVisitor{
        Object visit(Triangle t);
    }
    

    至此为止,有了1、2、3的代码,访问者模式的代码框架就已经构建起来了。如果需求分析没有变化,那么程序一直应用即可;如果需求分析发生变化,则基础功能类不用变化,只要定义IVisitor接口的具体功能实现类就可以了,例如求三角形重心坐标代码如下。
    4.定义重心坐标实现类CenterVisitor

    class Point{
        float x, y;
    }
    class CenterVisitor implements IVisitor{
        public Object visit(Triangle t){
            Point pt = new Point();
            pt.x = (t.x1+t.x2+t.x3)/3;
            pt.y = (t.y1+t.y2+t.y3)/3;
            return pt;
        }
    }
    

    一个简单的测试类如下。

    public class Test3 {
        public static void main(String[] args) {
            IVisitor v = new CenterVisitor();        //定义求重心具体访问者对象
            Triangle t = new Triangle(0,0,2,0,0,2);  //定义三角形对象
            Point pt = (Point)t.accept(v);           //通过访问者对象求三角形重心坐标
            System.out.println(pt.x+"\t"+pt.y);
        }
    }
    

    可以知道,如果再想增加一个求三角形外接圆半径功能,只需再定义一个新类实现IVisitor接口,在该类中完成求外接圆半径功能即可。

    8.命令模式

    顾名思义,命令模式一定是有命令发送者、命令接收者。命令发送者负责发送命令,命令接收者负责接收命令并完成具体的工作。

    命令模式主要针对需要执行的任务或用户提出的请求进行封装与抽象。抽象的命令接口描述了任务或请求的共同特征,而实现则交由不同的具体命令对象完成。每个命令对象都是独立的,它负责完成需要执行的任务,却并不关心是谁调用它。

    命令模式抽象UML类图
    在这里插入图片描述
    命令模式一般有4种角色,如下所示。
    ● ICommander:抽象命令者,是一个接口,规定了用来封装请求的若干个方法。
    ● ConcreteCommander:具体命令发送者,即命令源。它是实现命令接口的类的示例,如上文中的Teacher类。
    ● Invoker:请求者,具体命令的管理与维护类。请求者是一个包含“命令接口”变量的类的示例。请求者中的“命令”接口的变量可以存放任何具体命令的引用,请求者负责调用具体命令,让具体命令执行那些封装了请求的方法。
    ● Receiver:命令接收者,是一个类的示例。该示例负责执行与请求相关的操作,如上文中的Student类。

    考虑老师通知学生打扫卫生的程序描述,具体代码如下。
    1.抽象命令接口ICommand

    interface ICommand{
        public void sweep();
    }
    

    2.命令接收者Student

    class Student{
        public void sweeping(){
            System.out.println("we are sweeping the floor");
        }
    }
    

    在命令模式中,具体工作一定是在接收者中完成的,这一点非常重要。示例中“清扫”工作是由sweeping()方法完成的。
    3.命令发送者Teacher

    class Teacher implements ICommand{
        private Student receiver = null;
        public Teacher(Student receiver){
            this.receiver = receiver;
        }
        public void sweep(){  //发送sweep清扫命令
            receiver.sweeping();
        }
    }
    

    命令发送者类中,一般来说包含命令接收者的引用,表明发送命令的目的地址。所以Teacher类中定义了接收者Student类对象的引用。而实现的抽象接口方法中表明发送命令的具体过程,sweep()中利用方法转发说明具体的清扫工作是由接收者Student对象完成的。
    4.命令请求者类Invoke

    class Invoke{
        ICommand command;
        public Invoke(ICommand command){
            this.command = command;
        }
        public void execute(){
            command.sweep();  //启动命令
        }
    }    
    

    在这里插入图片描述
    在这里插入图片描述
    普通思路是命令发送者直接作用命令接收者,而命令模式思路是在两者之间增加一个请求者类,命令发送者与请求者作用,请求者再与命令接收者作用,请求者起到了一个桥梁的作用

    5.一个简单的测试类

    public class Test {
        public static void main(String[] args)
        {
            Student s = new Student();         //定义接收者
            Teacher t = new Teacher(s);        //定义命令发送者
            Invoke invoke = new Invoke(t);     //将命令请求加到请求者对象中
            invoke.execute();                  //由请求者发送命令
        }
    }
    

    9.装饰器模式

    装饰器模式利用包含代替继承,动态地给一个对象添加一些额外的功能。以消息日志功能为例,其装饰器模式UML类图如图所示
    在这里插入图片描述
    装饰器模式主要有如下4种角色。
    ● 抽象构件角色(Component):
    它是一个接口,封装了将要实现的方法,如ILogger。
    ● 具体构件角色(ConcreteComponent):
    它是多个类,该类实现了Component接口,如FileLogger、ConsoleLogger。
    ● 装饰角色(Decorator):
    它是一个抽象类,该类也实现了Component接口,同时也必须持有接口Component的对象的引用,如事例中Decorator。
    ● 具体的装饰角色(Decorator类的子类,可以有一个,也可以有多个):
    这些类继承了类Decorator,实现了Component接口,描述了具体的装饰过程,如UpLogger、XMLLogger。

    1.抽象装饰器基类Decorator

    abstract class Decorator implements ILogger{
        protected ILogger logger;
        public Decorator(ILogger logger){
            this.logger = logger;
        }
    }
    

    2.具体装饰类

    //信息大写装饰类UpLogger
    class UpLogger extends Decorator{
        public UpLogger(ILogger logger){
            super(logger);
        }
        public void log(String msg) {
            msg = msg.toUpperCase();     //对字符串进行大写装饰
            logger.log(msg);             //再执行已有的日志功能
        }
    }
    
        //XML格式化装饰类XMLLogger
        class XMLLogger extends Decorator{
              public XMLLogger(ILogger logger){
                  super(logger);
              }
              public void log(String msg) {
                  String s = "<msg>\r\n" +
                           "<content>"+msg+"</content>\r\n"+
                            "<time>" + new Date().toString()+ "</time>\r\n"+
                            "</msg>\r\n";
                  logger.log(s);
             }
         }
    

    3.一个简单的测试类

    public class Test {
        public static void main(String[] args)throws Exception {
            ILogger existobj = new FileLogger();     //已有的日志功能
            ILogger newobj= new XMLLogger(existobj); //新的日志装饰类,对existobj装饰
            String s[] = {"how", "are", "you"};        //仿真传送的字符串信息数组
            for(int i=0; i<s.length; i++){
                newobj.log(s[i]);
                Thread.sleep(1000);                  //每隔1 s传送一个新的字符串
            }
            System.out.println("End");
        }
    }
    

    10.组合模式

    文件树型结构示例图
    在这里插入图片描述
    根目录是由两个子目录组成的,第一级子目录由两个文件组成,第二级子目录由两个文件组成,因此树型形式也可以称作组合形式。把叶子节点与目录节点都看成相同性质的节点,只不过目录节点后继节点不为空,而叶子节点后继节点为null。这样就能够对树型结构的所有节点执行相同的操作,这也是组合模式的最大特点。采用组合模式实现文件树型结构的功能,具体代码如下。

    1.定义抽象节点类Node

    abstract class Node{
        protected String name;
        public Node(String name){
            this.name = name;
        }
        public void addNode(Node node)throws Exception{
            throw new Exception("Invalid exception");
        }
        abstract void display();
    }
    

    该类是叶子节点与目录节点的父类,节点名称是name。其主要包括两类方法:一类方法是所有节点具有相同形式、不同内容的方法,这类方法要定义成抽象方法,如display();另一类方法是目录节点必须重写,叶子节点无需重写的方法,相当于为叶子节点提供了默认实现,如addNode()方法,因为叶子对象没有该功能,所以可以通过抛出异常防止叶子节点无效调用该方法。

    2.文件叶子节点类FileNode

    class FileNode extends Node{
        public FileNode(String name){
            super(name);
        }
        public void display(){
            System.out.println(name);
        }
    }
    

    该类是Node的派生类,仅重写display()方法即可。

    3.目录节点类DirectNode

    class DirectNode extends Node{
        ArrayList<Node> nodeList = new ArrayList();
        public DirectNode(String name){
            super(name);
        }
        public void addNode(Node node)throws Exception{
            nodeList.add(node);
        }
        public void display(){
    
            System.out.println(name);
            for(int i=0; i<nodeList.size(); i++){
                nodeList.get(i).display();
            }
        }
    }
    

    该类从Node抽象类派生后,与原DirectNode类相比,主要有以下不同:①由定义两个集合类成员变量转为定义一个集合类成员变量nodeList; ②由定义两个添加方法转为定义一个添加方法addNode(); ③display()方法中,由两个不同元素的循环转为一个对相同性质节点Node的循环。也就是说,原DirectNode中不论是定义成员变量、成员方法,还是方法内部的功能,都要实时考虑叶子节点、目录节点的不同性,因此它的各种定义一定是双份的。而组合模式中认为叶子节点、目录节点是同一性质的节点,因此与原DirectNode类对比,它的各种定义工作一定是减半的,也易于扩充。

    4.一个简单的测试类

    public class Test {
        public static void createTree(Node node)throws Exception{
            File f = new File(node.name);
            File f2[] = f.listFiles();
            for(int i=0; i<f2.length; i++){
                if(f2[i].isFile()){
                    Node node2 = new FileNode(f2[i].getAbsolutePath());
                    node.addNode(node2);
                }
                if(f2[i].isDirectory()){
                    Node node2 = new DirectNode(f2[i].getAbsolutePath());
                    node.addNode(node2);
                    createTree(node2);
                }
            }
        }
        public static void main(String[] args)throws Exception {
            Node start = new DirectNode("d://data");
            createTree(start);
            start.display();
        }
    }
    

    通过该示例,可得组合模式更一般的UML类图,如图所示。共包括以下三种角色。
    在这里插入图片描述
    ● 抽象节点:Node,是一个抽象类(或接口),定义了个体对象和组合对象需要实现的关于操作其子节点的方法,如add()、remove()、display()等。
    ● 叶节点:Leaf,从抽象节点Node派生,由于本身无后继节点,其add()等方法利用Node抽象类中相应的默认实现即可,只需实现与自身相关的remove()、display()等方法即可。
    ● 组合节点:Component,从抽象节点Node派生,包含其他Composite节点或Leaf节点的引用。
    总之,若某应用可形成树型结构,而且形成树型结构后可对叶节点及中间节点进行统一的操作,那么采用组合模式构建应用功能是一个比较好的选择。

    资料来自《Java设计模式深入研究》

    展开全文
  • 面向对象思想设计原则 •在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想设计原则 •单一职责原则 •开闭原则 •里氏替换原则 •依赖注入原则 •接口分离原则 •...
    面向对象思想设计原则
    在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设计原则
    单一职责原则
    开闭原则
    里氏替换原则
    依赖注入原则
    接口分离原则
    迪米特原则


    l单一职责原则
    其实就是开发人员经常说的 高内聚,低耦合
    也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个。在设计模式中,所有的设计模式都遵循这一原则



    l开闭原则
    核心思想是:一个对象对扩展开放,对修改关闭。
    其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。
    也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢 ? 这就需要借助于抽象和多态,即把可能变化的内容抽象出来,从而使抽象的部分是相对稳定的,而具体的实现则是可以改变和扩展的。


    l里氏替换原则
    核心思想:在任何父类出现的地方都可以用它的子类来替代。
    l 接口分离原则
    核心思想:不应该强迫程序依赖它们不需要使用的方法。
    其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口中。
    其实就是说:同一个继承体系中的对象应该有共同的行为特征。


    l依赖注入原则
    核心思想:要依赖于抽象,不要依赖于具体实现。


    其实就是说:在应用程序中,所有的类如果使用或依赖于其他的类,则应该依赖这些其他类的抽象类,而不是这些其他类的具体类。为了实现这一原则,就要求我们在编程的时候针对抽象类或者接口编程,而不是针对具体实现编程。


    l接口分离原则
    核心思想:不应该强迫程序依赖它们不需要使用的方法。
    其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口中。


    l迪米特原则
    核心思想:一个对象应当对其他对象尽可能少的了解
    其实就是说:降低各个对象之间的耦合,提高系统的可维护性。在模块之间应该只通过接口编程,而不理会模块的内部工作原理,它可以使各个模块耦合度降到最低,促进软件的复用


    设计模式概述
    设计模式( Design pattern )是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
    设计模式不是一种方法和技术,而是一种思想
    设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,是设计的程序可复用
    学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成

    l设计模式的几个要素
    名字 必须有一个简单,有意义的名字
    问题 描述在何时使用模式
    解决方案 描述设计的组成部分以及如何解决问题
    效果 描述模式的效果以及优缺点
    l设计模式的分类
    创建型模式 对象的创建
    结构型模式 对象的组成 ( 结构 )
    行为型模式 对象的行为


    l简单工厂模式概述
    又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
    l优点
    客户端不需要在负责对象的创建,从而明确了各个类的职责
    l缺点
    这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护


    l工厂方法模式概述
    工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
    l优点
    客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
    l缺点
    需要额外的编写代码,增加了工作量


    l单例设计模式概述
    单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供。
    l优点
    在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
    l缺点
    没有抽象层,因此扩展很难。
    职责过重,在一定程序上违背了单一职责


    l模版设计模式概述
    模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现
    l优点
    使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求
    l缺点

    如果算法骨架有修改的话,则需要修改抽象类



    l装饰设计模式概述
    装饰模式就是使用被装饰类的一个子类的实例,在客户端将这个子类的实例交给装饰类。是继承的替代方案
    l优点
    使用装饰模式,可以提供比继承更灵活的扩展对象的功能,它可以动态的添加对象的功能,并且可以随意的组合这些功能
    l缺点
    正因为可以随意组合,所以就可能出现一些不合理的逻辑


    l适配器设计模式概述
    将一个类的接口转换成另外一个客户希望的接口。从而使原来不能直接调用的接口变的可以调用。
    l优点
    让本来不适合使用的接口变得适合使用
    l缺点
    一次只能适配一个类,使用有一定的局限性


    以后还有在补充, 先记录到这里。













    展开全文
  • 设计模式试题-答案

    千次阅读 2018-12-25 17:55:27
    1、设计模式一般用来解决什么样的问题( a) A.同一问题的不同表相 B不同问题的同一表相 C.不同问题的不同表相 D.以上都不是 2、下列属于面向对象基本原则的是( c ) A.继承 B.封装 C.里氏代换 D都不是 3、Open-Close...
  • Java 日志框架解析:设计模式、性能

    千次阅读 2017-09-28 10:00:54
    在平常的系统开发中,日志起到了重要的作用,日志写得好对于线上问题追踪有着很大的帮助。一个好的日志框架,既要方便...研究一款开源项目,学到的不仅仅是这个项目本身,还会学到很多设计思想,可以利用到日常工作中。
  • 学习Spring系列,永远离不开的就是IOC控制反转和AOP面向切面编程,并且在其中充满了设计模式的魅力. 之前面试也被问到过,简单的理解过程是不够的,败在了理解源码上面,为了今后的学习,想用源码去理解一下到底什么...
  • 01面向对象计算器_封装版 02面向对象计算器_继承多态虚方法版 03面向对象计算器_抽象类版 04面向对象计算器_接口版 ...06面向对象计算器_简单工厂模式 07委托多态计算器 08计算器终极版_插件机制(反射)
  • 23种设计模式图解

    千次阅读 2019-01-14 20:22:57
    还是一个降低类之间的耦合度的意思,从这个我们看出,其实设计模式就是一个软件的设计思想, 从大型软件架构出发,为了升级和维护方便,要降低依赖,降低耦合 5.迪米特法则(最少知道原则)(Demeter Principle)...
  • 设计模式思想还远未广泛应用

    千次阅读 2013-09-22 22:17:49
    1994年,在波特兰举行的OOPSLA(Object Oriented Programming, Systems, Languages and Applications)大会上,Addison-Wesley出版社展示了一本新书——《设计模式》。此后15年,它以各种语言在全球发行,成为总销量达...
  • 设计模式——设计模式概述

    万次阅读 多人点赞 2019-10-12 08:07:49
    软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式主要是为了解决某类重复出现的问题而出现的一套成功或有效的解决方案。设计模式提供...
  • Head First设计模式(完整高清版).pdf,涵盖了各种宝贵的设计思想
  • 《Spring设计思想》AOP设计基本原理

    万次阅读 多人点赞 2016-04-10 20:36:07
    Spring 提供了AOP(Aspect Oriented Programming) 的支持, 那么,什么是AOP呢?本文将通过一个另外一个角度来诠释AOP的概念,帮助你更好地理解和使用Spring AOP。... 引入了代理模式的Java程序执行流(AOP实现的机制) 4.
  • 图解Java设计模式(一)

    万人学习 2019-02-27 21:06:35
    2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,...
  • JAVA设计模式

    千次阅读 多人点赞 2017-12-21 21:40:49
    JAVA设计模式
  • 二、7个设计原则 1、单一职责原则 ( SRP ) 2、开闭原则 ( OCP ) 3、里氏替换原则 ( LSP ) 4、依赖倒置原则 ( DIP ) 5、接口隔离原则 ( ISP ) 6、最少知道原则(迪米特原则) 7、合成/聚合复用(CARP) 三、...
  • 设计模式: 软件分层架构思想

    千次阅读 2018-09-11 18:58:04
    分层架构设计思想,有很多成功的例子,诸如:OSI七层网络模型,通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯,因此其最主要的功能就是帮助不同类型的主机实现数据传输。OSI网络模型是理论模型...
  • 简述MVC设计思想

    千次阅读 2018-03-26 11:48:53
    它是一中软件的设计思想,将应用的一个输入、处理、输出按照模型层,视图层,控制层进行分层设计。 1)模型: 业务逻辑包含了业务数据的加工与处理以及相应的基础服务(为了保证业务逻辑能够正常进行的事务、安全、权限...
  • 简介: c++ 设计模式(8大设计原则、23中设计模式)李建忠 笔记总结 文章目录本博文的简述or解决问题?重要提示:重新认识面向对象面向对象设计原则(一共八种)将设计原则提升为设计经验C++设计模式(一共23种)本...
  • MapReduce设计模式.pdf 个人收集电子书,仅用学习使用,不可用于商业用途,如有版权问题,请联系删除!
  • android源码设计模式解析与实战.pdf下载 完整版高清

    千次下载 热门讨论 2016-12-02 19:35:05
    本书从Android源码的角度由浅入深地剖析设计模式的运用,让工程师们把设计与模式重视起来,提升自己的设计能力与代码质量。因此本书适合的读者为初、中、高级Android工程师。另外,设计思想都是相通的,其他领域的...
  • 面向对象思想设计原则 单一职责原则 开闭原则 里氏替换原则 依赖注入原则 接口分离原则 迪米特原则 设计模式的分类 简单工厂模式 简单工厂模式概述 工厂方法模式 工厂方法模式概述 ...适配器设计模式
  • 设计模式 原型模式 设计思想 演过过程 重构过程
  • 软件设计模式详解

    万次阅读 多人点赞 2018-11-07 21:40:21
    软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 ...
  •  其实设计模式是人们实践的产物,在初期的开发过程中好多人发现再进行重复的代码书写,那些开发大牛们就不断总结、抽取最终得到了大家的认可于是就产生了设计模式,其实设计模式的种类可以分为23种左右,今天主要和...
  • 软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。...
  • 经典设计模式实战演练

    千次阅读 2018-07-03 02:45:11
    为了实现以上目的,前辈们从实践中总结出了一套可套用的武功招式,这就是设计模式。使用设计模式可以让你写出一手令人赏心悦目的代码。 我认为每一个后端开发者都应该学习设计模式,它是代码的精华,是程序发展的...
  • 设计模式23模式介绍

    万次阅读 多人点赞 2020-01-18 08:20:52
    一、什么是设计模式 设计模式是一套被反复使用、多数人知晓的、经过分类编写的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式使代码编程真正...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 361,080
精华内容 144,432
关键字:

设计模式思想