首页 > 编程知识 正文

面向对象设计设计模式,面向对象编程设计

时间:2023-05-04 21:05:10 阅读:218779 作者:923

前言

设计模式(design pattern)是一套被反复使用、多数人知晓、经过分类编目的优秀代码设计经验的总结。关键词:重用代码、工程化、面向对象。设计模式起源于建筑设计学,最先由 Gang of Four   提升到了理论高度。

可复用面向对象体系分为两大系统:工具箱和框架。Java中的API属于工具箱(toolkit),Java EE (Enterprise Edition)属于框架(Framework)。设计模式是大神们在构造 Java EE 的时候的重要理论依据,学习设计模式有助于深入了解 Java EE。

我最近在实验楼 学习完了一门课程《Java进阶之设计模式》。截止至2015年12月16日,我已经在实验楼网站有效学习了960分钟,完整学习了5门课程。功夫在课外,我认为实验楼是一个能够开阔视野,快速入门新领域的地方。其主要特点是:课程设置广泛,内容深入浅出,提供linux环境。

GOF最早提出的设计模式总共有23个,分为三类型:创建型模式(5个),构造型模式(7个),行为型模式(11个)。后来,人们总结出了更多的设计模式,参考wikipedia

创建型:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式构造性:适配器模式、装饰模式、代理模式、组合模式、桥梁模式、外观模式、享元模式行为型:模板方法模式、命令模式、责任链模式、迭代器模式、中介者模式、观察者模式、访问者模式、状态模式、解释器模式

实验楼里面讲解了其中的6个,这6个大体上是23个中使用频率最高的6个:工厂方法模式、抽象工厂模式、单例模式、适配器模式、装饰者模式、观察者模式。我下面将首先简单介绍设计原则,然后小结一下上述常用6种模式。我写本篇博客使用的参考资料包括:实验楼的课程、《Head First Design Patterns》、《设计模式(Java版)》、wikipedia、百度百科。

设计原则

开闭原则(OCP):open for extension, but close for modification。在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。这个是最最基础的原则。

单一职责原则(SRP):never be more than one reason for a class to change。专注做一件事情,仅有一个引起变化的原因,“职责”可以理解成“变化的原因”。唯有专注,才能够保证对象的高内聚;唯有单一,才能保证对象的细粒度。

里氏替换原则(LSP):Liskov提出:” Let  Φ(x) be a property provable about objects x of type T. Then  Φ(y) should be true for objects y of type S, where S is a subtype of T.” 这里的type,我理解成class。子类的对象可以无条件地替换父类的对象,并且不引起程序的改变。或者说:只要父类能出现的地方,子类就可以出现。

依赖倒置原则(DIP):High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions. 即高层模块不依赖低层模块;高、低层模块都依赖其抽象;抽象不依赖细节,反过来细节依赖抽象。在JAVA中,所谓的抽象,就是接口或者抽象类;所谓细节,就是就实现类(能够实例化生成对象的类)。为什么说“倒置”?因为在传统的面向过程的设计中,高层次的模块依赖于低层次的模块,抽象层依赖于具体层(这样不好),倒置过来后,就成为了面向对象设计的一个原则了(这样子好)。

接口隔离原则(ISP):The dependency of one class to another should depend on the smallest possible interface. 类间的依赖关系应该建立在最小的接口上面。客户端不应该依赖他不需要的接口,只提供调用者需要的方法,屏蔽不需要的方法。一个接口代表一个角色,使用多个专门的接口比使用单一的总接口更好。

迪米特法则(LoD)又称最少知识原则(LKP): Each unit should only talk to its friends; don’t talk to strangers. Only talk to your immediate friends. Each unit should have only limited knowledge about other units. 曾经在美国有一个项目叫做Demeter。LoD is a specific case of loose coupling.此原则的核心观念就是类之间的弱耦合,在这种情况下,类的复用率才可以提升。

工厂方法模式

Head First (简称HF ) 说:There is more to making objects than just using the new operator. Instantiation is an activity that shouldn’t always be done in public and can often lead to coupling problems. 这就是工厂方法的来源。

首先简单提一下:简单工厂。HF : The Simple Factory isn’t actually a Design Pattern; it’s more of a programming idiom. 代码实现:把 new操作的过程封装到一个class SimpleFactory 的一个方法中。这个方法有一个参数,这个参数决定如何new。

简单工厂进行抽象化,得到工厂方法模式。工厂方法模式定义:Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method let a class defer instantiation to subclasses. 简而言之,一个工厂父类作为“自觉的钢笔”,管理旗下的具体工厂子类,new 操作在具体工厂子类里面。定义中”defer”的意思是:父类不立刻进行new操作,而是交给子类进行new操作。

代码:工厂方法模式例子Java源代码 (推荐在新标签页打开)。我改编自HF 的pizza例子(我本学期早上流行吃包子)

小结:(看完代码之后再看小结)
一个工厂子类,看上去很像一个简单工厂。确实如此,不过这一些工厂子类都继承自同一个工厂父类,需要实现同一个抽象方法createBaoZi,然后利用多态性。简单工厂像是一个“一锤子买卖”,而工厂方法模式则搭建了一个框架,让工厂子类决定生产那一个具体产品。工厂方法模式更加抽象,更具有通用性,耦合度更低。

在Main类里面,new 一个工厂子类,把其引用赋给一个工厂父类的引用。从代码层面可以看出,当需要扩充新的工厂的时候,增加一个继承工厂父类的子类就行了。Main类里面的那个工厂父类的引用无需改变。更进一步说,Main类里面的所有的用到工厂父类的引用的地方都无需改变,这就是体现了开闭原则的中的“close for modification”

抽象工厂模式

抽象工厂模式定义:Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.

首先需要知道一个概念“a family of products”,翻译成“产品族”。Head First : Factory Method provides an abstract interface for creating one product. Abstract Factory provides an abstract interface for creating a family of products.

产品族:假设有三类抽象产品:手机、笔记本、平板。手机分为两个具体产品:iphone 6s和华为Mate8;电脑分为两个具体产品:Macbook Pro和Surface Book;平板分为iPad Air和Surface 3。那么从手机里面二选一,从笔记本里面二选一,从平板里面二选一,总共产生了8个不同的产品族。比如”iphone 6s + Macbook Pro + iPad Air”就是8个产品族中的1个(感性的眼神!)。

代码:抽象工厂模式例子Java源代码 (推荐在新标签页打开)

小结:抽象工厂模式是对工厂方法的进一步抽象。是把一组具有同一主题的单独的工厂封装起来。抽象工厂可以看成是”工厂的工厂“,抽象工厂中的一个抽象方法,很像一个工厂方法模式。一个工厂有多抽象工厂,就像是有多个工厂方法模式。

单例模式

有时候存在这种需求:强制要求某个类只能实例化一个对象, one and only one. 单例模式解决了这种需求,其定义是:Singleton Pattern ensures a class has only one instance, and provide a global point of access to it.

应用场景:

要求生成唯一序列号的环境需要共享访问点或共享数据,例如CSDN每一篇博客都有一个计数器,用来统计阅读人数,使用单例模式保持计数机的值需要创建的对象消耗大量资源,比如IO和数据库资源需要定义大量的静态常量或者静态方法(工具类)的环境,比如Java基础类库中的java.lang.Runtime类

仔细想想,如果使用全局变量,则可以实现定义中的后半句,但是无法实现定义中的前半句,而且使用全局变量会污染命名空间。

代码:单例模式Java源代码,可以在新标签页打开

小结:单例模式,顾名思义,让一个类有且只有一个实例对象。这样做可以达到节约或者控制系统资源的目的。在代码层面,其最主要的特征是其构造函数是私有的。次要特点是:数据成员Singleton的实例引用是静态的,而且有一个静态的getInstance()方法,用来负责 new Singleton() 和返回 Singleton的实例引用。

观察者模式

这是一个常用的行为型模式,又称为“发布者——订阅者”模式。发布者比如报社,订阅者比如老百姓。清晨高兴的导师们出去晨练,看见一个卖报纸的qxdds在街上大声吆喝:“今天的报纸来了!”,然后高兴的导师们得到通知,都去买了报纸。报社是主题(Subject),高兴的导师们是观察者(Observer),卖报纸的qxdds,负责告诉Observer:“Subject更新了!”

定义:The Observation Pattern defines a one-to-many dependency between objects so that when one objects changes state, all of its dependents are notified and updated automatically.

代码:观察者模式Java代码,可以在新标签页打开

小结:定义中的one就是Subject, many就是Observers;one就是发布者,many就是订阅者;one就是事件源,many就是监听者。多个观察者(Observer)“围观”一个被观察者(Subject),可以说被观察者是万众瞩目的焦点。观察者和被观察者之间是抽象耦合(类图在上面的链接里),它们属于不同的抽象化层次,非常容易扩展。使用场景是:关联行为;事件多级触发;消息队列等。

适配器模式

这是一个结构型模式。周边适配器到处都是,比如手机充电器就是一个把插座上面的两孔国标插座,转换成USB接口。去了美国,怎么给我的荣耀手机充电?那就那一个适配器,把美国的两孔/三孔美标插座转换成两孔国标插座。

定义:The Adapter Pattern converts the interface of a class into another interface the client expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

在上面的情景中,荣耀手机就是定义中的“client”;两孔国标接口就是”interface the client expect”;美国的两孔/三孔美标插座就是定义中 “converts the interface of a class”中的”interface”;Adapter 负责动词”convert”。

代码:适配器模式 Java源代码,可以在新标签页中打开

小结:适配器Adapter的核心,是实现Target接口, 组合Adaptee接口。通过实现和组合,这两种类与类之间的关系,把两个本不兼容的类(Target 和 Adaptee)联系在一起。增强了类的透明性,松耦合,提高了类的复用,增强了代码的灵活性。

装饰者模式

这是一个结构型模式。

很多情况下,需要扩展功能,增加职责。如果说生成子类是静态的添加额外的职责的话,那么装饰者模式则提供了一种动态的方法,较为灵活。

定义:attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

代码:装饰者模式 Java源代码,可以在新标签页中打开

小结:关键是Decorator同时继承和组合Component,Component是被装饰者装饰的对象。装饰者和被装饰者可以独立发展,耦合度很低,很好的符合了开闭原则,是继承关系的一种替代方案。或者说,是一种对继承关系的有力的补充,可以解决类膨胀的问题。Java.IO就是参照装饰者模式设计的。

一点感悟

我现在是计算机科学与技术(CS)的大三上学期。设计模式的学习,我都是利用课外时间。我学习设计模式的初衷,除了见见世面之外,就是学习Java(我大一大二都是写C++,大三上学期才学Java),可谓一箭双雕。我下载了《Head First Design Patterns》在GitHub上的样例代码, which is written in Java。我一边看书,一边看代码,抄代码,一边改编代码。理论与敲代码结合,快速提升、强化基本能力。

敲了不少Java代码,对Java的”感觉”加深了,代码是需要积累的我在eclipse装一个插件,用来绘制UML类图。我对eclipse的”感觉”加深了,体会到了插件的强大威力继承,多态。以前写C++代码,只用封装,很少用继承和多态。毕竟平时主要在写”小算法”,没有涉及到大的宏观层面的设计。在设计模式中,大量运用继承(还有实现),多态decouple。这个词在HF 中高频率出现。降低耦合,面向接口,可以增强整个程序的扩展性,便于维护,适合多团队多人合作开发通过几个设计模式,慢慢体会了设计模式中的6条原则,这些原则不是”教条主义“,不能刻板遵守。而是要慢慢把这些思想融入到程序设计中关于算法和设计模式。网上看到一些评论,有一个评论很生动:算法像是”单兵作战和武器装备“,设计模式像是”仗列的阵型“。算法用来解决具体问题,设计模式用来合理的把算法隔离到各个正确的地方去。真正体会设计模式,还是需要很多年的实践积累

设计模式的博客就写到这里。最近在较短时间内,集中学习了6个常用设计模式,收获颇丰。掌握了基本思想和方法,在以后的学习和实践中,遇到新的需要使用的模式,我就能快速学会和运用。

一个设计模式学习网站

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。