深入浅出设计模式(1)
来源:互联网 发布:神知世界txt下载 编辑:程序博客网 时间:2024/05/21 14:56
故学然后知不足,教然后知困。知不足,然后能自反也;知困,然后能自强也,故曰:教学相长也。——礼记
⋅ 学记
OOD(面向对象设计)如何才算是好的呢?我们可以用GRASP模式原则指导。
GRASP(General Responsibility Assignment Software Patterns)
- General / 通用的、抽象的、广泛应用的
- Responsibility/ 责任、义务、职责
- Assignment /分配责任于一个模块或类
- Software /计算机代码、软件
- Patterns/规律、模板、抽象或模式
GRASP系列模式分为9种,详述这9种模式。
- Information Expert 信息专家
最基本的原则,如果某个类在某方面具有完整信息,足以实现某个责任,就将这个责任分配给这个类。
比如说程序要检验两个商品是否是同一个商品,而商品编码在建模中描述为ProductID,哪个类具有这一项呢?就是Item类,根据信息专家原则,Item类应该包括检测责任。 Creator 创造者
以下情况,类A应该具有创建类B的责任:
(1) A是B的聚合
(2) A是B的容器
(3) A有初始化B的数据
(4) A记录B的实例
(5) A频繁使用BLow Coupling 低耦合
(1) 低耦合使得一个类的修改对其他类的影响范围有所降低
(2) 系统维护更容易
(3) 使得类更容易理解,因为类会变得简单、专业、高内聚
不要对陌生人说话
不要连接两个不需要通信的对象
两个模块中的内部类间连接是一个大错误High Cohesion 高内聚
使内聚保持最高,目的是为了提高设计类的重用性,并且控制类设计的复杂程度。
含义就是努力的使得分出来的类具有独立的责任。
比如一个类单独处理很多不同模块的事务,比如一个类既处理对数据的存取,又处理用户接口操作或图形处理,这种跨模块的设计就是非常低的内聚。
低类聚将会导致:
(1) 很难被理解和维护
(2) 难以实现类的重用
(3) 系统变得脆弱,不断需要修改Controller 控制器
系统事件的接收和处理通常由一个高级类来代替,一个子系统会有很多控制器类,分别处理不同的事务。
人们通常将接受和处理系统事件的职责分配给以下类,这些类也是控制器类:
(1) 能全面代表系统、设备或子系统的类
(2) 可以代表系统事件发生时用例发生情景的类
(3) 代表某些卷入真是世界应用中活动的类,例如人物角色控制器类。
比如银行系统中,用一个控制器处理所有银行事务,即类TransactionController。包括
deposit(), withdraw(), payBill(), transfer();
大家常用的MVC三层架构强调了控制模式的应用。Polymorphism 多态
如果相关的行为只是由于种类不同,可以分配相关责任给指定的种类。
比如定义一个抽象形状类shape,矩形、圆形、椭圆形都重写shape类的draw方法,使用这种多态机制,将绘画的责任分配给指定的类。这样新的形状加入系统后,不会对其他类有任何影响。Pure Fabrication 纯虚构
实现高内聚和低耦合都是系统设计的目标,但是高内聚和低耦合是矛盾的。因为高内聚往往意味着类的数量增多,对象间要合作完成任务,使得耦合增高。
要解决这个矛盾,可以应用纯虚构模式,它增加了高内聚的特征。抽象工厂模式是纯虚构模式的一种实际体现。- Indirection 间接
避免对象间直接的耦合,可以将协调组件或服务的职责分配给中间对象,中间对象称为间接或中介对象。
直接耦合两个系统往往会引起维护的困难,间接模式就是一个解决方案,引入中间对象可以使得两个子系统的重用性得到提高。比如人事系统中岗位及员工之间的关系,员工分配在岗位上,它们有连接。但是员工和岗位都是独立的,所以我们需要设计一个中间类——分配。 - Protected Variations 受保护变化
找出预计有变化或不稳定的点,为这些变化的点创建稳定的接口,比如游戏开发商致力于开发可通用的游戏引擎,它是个外层包装模块,使用相同的游戏引擎可以开发出不同的游戏。
受保护变化可以理解为开闭原则,一个软件实体应该对扩展开放,对修改关闭。
创建型设计模式
简单工厂模式
定义:
专门定义一个类来负责创建其他类的实例,被创建的实例具有共同的父类。又称为静态工厂方法(static factory method)。
public interface Mobile{ public void call();}public class Nokia implements Mobile{ public void call(){ System.out.println("nokia手机"); }}public class Motorola implements Mobile{ public void call(){ System.out.println("Motorola手机"); }}public class MobileFactory{ public Mobiel getMobile(String title) throws Exception{ if(title.equalsIgnoreCase("nokia")){ return new Nokia(); } else if(title.equalsIgnoreCase("motorola")){ return new Motorola(); } else{ throw new Exception("no such"+title+"mobile found"); } }}public class SimpleFactoryClient{ static public void main(String argv[]){ try{ MobileFactory mf = new MobileFactory(); Mobile m; m = mf.getMobile("nokia"); m.call(); m = mf.getMobile("motorola"); m.call(); } catch(Exception e){ e.printStackTrace(); } }}
优点:
外界可以从直接创建具体产品对象的尴尬局面中摆脱出来,不必管这些对象是如何创建以及如何组织的。
缺点:
全部创建逻辑都集中到一个工厂类,当系统中具体产品类不断增多时,可能会出现要求工厂类根据不同条件创建不同实例的需求。这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的扩展和维护也非常不利。
应用情景:
1,工厂类负责创建的对象比较少;2,客户只知道传入工厂类的参数,对于如何创建对象不关心。
工厂方法模式
定义:
工厂方法模式又叫虚拟构造器模式,或者多态工厂,类的创建型模式。父类负责定义创建对象的公共接口,子类负责生成具体的对象,将类的实例化操作延迟到子类中完成,既由子类来决定究竟应该实例化哪个类。
//手机接口public interface Mobile{ public void call();}//手机工厂接口public interface MobileFactory{ public Mobile produceMobile();}//摩托罗拉手机实现手机接口public class Motorola implements Mobile{ public void call(){ System.out.println("摩托罗拉手机"); }}//诺基亚手机实现手机接口public class Nokia implements Mobile{ public void call(){ System.out.println("诺基亚手机"); }}//摩托罗拉工厂实现生产手机方法public class MotorolaFactory implements MobileFactory{ public Mobile produceMobile(){ System.out.println("摩托罗拉工厂制造了"); return new Motorola(); }}//诺基亚工厂实现生产手机方法public class NokiaFactory implements MobileFactory{ public Mobile produceMobile(){ System.out.println("诺基亚工厂制造了"); return new Nokia(); }}//客户程序public class Client{ public static void main(String argv[]){ MobileFactory mf; Mobile m; mf = new MotorolaFactory(); m = mf.produceMobile(); m.call(); mf = new NokiaFactory(); m = mf.produceMobile(); m.call(); }}
优点:
客户只关心抽象产品和抽象工厂,完全不用理会返回的是哪一种具体产品,不用关心它是如何被具体工厂创建的。
(1)工厂角色和产品角色的多态性设计是工厂方法模式的关键,它能够使工厂可以自主确定创建何种产品对象,创建产品对象的细节封装在具体工厂内部。
(2)在系统中加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端。也不用修改其他的具体工厂和具体产品,只要添加一个具体工厂和一个具体产品就可以了。
优秀的面向对象设计鼓励使用封装和委托,封装是通过抽象工厂来体现的,委托是通过抽象工厂将创建对象的责任完全交给具体工厂来体现。
应用情景
1. 类不知道自己要创建哪一个对象。
2. 类用它的子类来指定创建哪个对象。
3. 客户需要清楚创建了哪一个对象
抽象工厂模式
定义
提供一系列相关和相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
抽象工厂模式与工厂方法模式最大的不同在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构。在抽象工程模式中,经常会用到产品族这一个概念。
//cpu接口public interface cpu{ public string getCPU();}//AMD类,实现cpu接口public class AMD implements CPU{ public String getCPU(){ return "Athlon XP 2800+"; }}//Intel类,实现cpu接口public class Intel implements CPU{ public String getCPU(){ return "奔腾4"; }}//硬盘接口public interface HardDisk{ public String getSize();}//Maxtor 实现硬盘接口public class Maxtor implements HardDisk{ public String getSize(){ return "MaXLIne Plus II 200G"; }}//定义WestDigit 实现硬盘接口public class WestDigit implements HardDisk{ publis String getSize(){ return "WD2500JD 250G"; }}//定义主板接口public interface MainBoard{ public void Attach(CPU cpu) throws Exception;}//主板微星,支持Intel的CPUpublic class MSI865PE implements MainBoard{ public void Attach(CPU cpu) throws Exception{ if(cpu.getClass().toString().endsWith("Intel")){ System.out.println("MSI865PE"); } else{ throw new Exception("主板MSI765PE只能配Intel的CPU"); } }}//主板微星,支持AMD的CPUpublic class MSIK7N2G implements MainBoard{ public void Attach(CPU cpu) throws Exception{ if (cpu.getClass().toString().endsWith("AMD")){ System.out.println("MSIK7N2G"); } else{ throw new Exception("主板MSIK7N2G只能配AMD的CPU"); } }}//定义抽象电脑工厂类public abstract class ComputerFactory{ CPU cpu; HardDisk hd; MainBoard mb; public void main(){ try{ System.out.println(this.getClass().getName().toString()); System.out.println(cpu.getCpu()); System.out.println(hd.getSize()); mb.Attach(cpu); }catch(Exception e){ System.err.println(e.getMessage()); } }}//抽象电脑工厂类派生类,定义其返回的系列配件产品public class IBM extends ComputerFactory{ IBM(){ cpu = new Intel(); hd = new WestDigit(); mb = new MSI865PE(); }}//客户程序调用:public class Client{ public static void main(String argv[]){ IBM ibm = new IBM(); ibm.show(); Dell dell = new Dell(); dell.show(); }}
优势:
抽象工厂模式的主要优点是隔离了具体类的生成,是的客户不需要知道什么被创建了。由于这种隔离,更换一个具体工厂就变得相对容易,所有具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
建造者模式
定义
将一个复杂对象的构建与它的表示分离,使得同样构建过程可以创建不同的表示。建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不知道内部具体构建细节。
其中类与对象之间关系为:
Builder:抽象建造者 为创建一个Product对象各个部件指定抽象接口
ConcreteBuilder: 具体建造者,实现Builder接口,构造和装配产品各个部件;定义并明确它们所创建的表示;提供一个返回这个产品的接口。
Director: 指挥者,构建一个使用Builder接口的对象。
Product: 产品角色:被构建的复杂对象,具体建造者创建该产品的内部表示并定义它的装配过程;包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
为什么需要Director,Director类的作用是巨大的。
第一,它隔离了客户及生产过程,
第二,它负责控制产品的生成过程。
比如你要去买车子,选好车型、颜色、内外饰等,交给Director,Director告诉你去某车间取车就可以。
Builder模式与AbstractFactory模式的区别
建造者模式与抽象工厂模式很像,但是Builder模式返回完整的一个产品,而AbstractFactory返回一系列产品;
在抽象工厂模式中,客户采用AbstractFactory生成自己要用的对象。
而在建造者模式中,客户指导Builder类如何去生成对象,或是如何合成一些类来构成建造类,侧重于一步步构造一个复杂对象,然后将结果返回。
//定义House接口public interface House{ boolean GetBackyard(); long NoOfRooms(); String Description();}//房间类public class Room{ public String RoomName;}//定义Apartment公寓,有3间房间,没有后院public class Apartment implements House{ private boolean mblnBackyard; private Vector Rooms; public Apartment(){ Room room = new Room(); Rooms = new Vector(); room.RoomName = "Master Room"; Rooms.addElement(room); room = new Room(); room.RoomName = "Second Bedroom"; Rooms.addElement(room); room = new Room(); room.RoomName = "Living Room"; Rooms.addElement(room); mblnBackyard = false; } public boolean GetBackyard(){ return mblnBackyard; } public long NoOfRooms(){ return Rooms.size(); } public String Description(){ String strDescription; strDescription="这是一间公寓,有"+Rooms.size()+"间房间\n"; strDescription=strDescription+"这间公寓没有后院"; for(int i=1;i<=Rooms.size();i++){ strDescription = strDescription + i +((Room)Rooms.elementAt(i-1)).RoomName; } return strDescription; }}//定义单一家庭房屋public class SingleFamilyHome implements House{ private boolean mblnBackyard; private Vector Rooms; public SingleFamilyHome(){ Room room = new Room(); Rooms = new Vector(); room.RoomName = "master bedroom"; Rooms.addElement(room); room = new Room(); room.RoomName = "second bedroom"; Rooms.addElement(room); room = new Room(); room.RoomName = "third Room"; Rooms.addElement(room); ... mblnBackyard = true; } public boolean GetBackyard(){ return mblnBackyard; } public long NoOfRooms(){ return Rooms.size(); } public String Description(){ String strDescription; strDescription ="这是一间公寓,有"+Rooms.size()+"间房间"; for(int i=1;i<=Rooms.size();i++){ strDescription = strDescription + i + ((Room)Rooms.elementAt(i-1)).RoomName; } return strDescription; }}//Director根据客户传入的mblnBackyard参数的值,创建不同的House:public class Director{ public House BuildHouse(boolean mblnBackyard){ if(mblnBackyard){ return new SingleFamilyHome(); } else{ return new Apartment(); } }}//客户程序通过调用Director的BuildHouse方法建造房屋,传入参数决定房屋类型public class Client{ public static void main(String argv[]){ Director director = new Director(); House house = director.BuildHouse(false); System.out.println(house.Description()); }}
应用场景:
下面情景适合应用建造者模式:
(1) 创建复杂对象的算法是独立于它的组成部件及装配过程
(2) 构造的过程允许构造对象有不同的表现
参考资料:
深入浅出设计模式,清华大学出版社
- 深入浅出设计模式(1)
- 深入浅出设计模式(一)
- 深入浅出设计模式(二)
- 深入浅出设计模式(四)
- 深入浅出设计模式-学习笔记(1) Strategy
- 深入浅出设计模式-读书心得1
- 深入浅出设计模式(C#/Java版)
- 深入浅出设计模式(影印版 ) 读书笔记
- 读《深入浅出设计模式》
- 《深入浅出设计模式》小结
- 《深入浅出设计模式》笔记
- 深入浅出工厂设计模式
- 深入浅出设计模式
- 深入浅出设计模式(1)——单件模式(Singleton Pattern)
- 深入浅出设计模式-005:单例模式(Singleton Pattern)
- 深入浅出设计模式-010:迭代器模式(Iterator Pattern)
- 深入浅出设计模式-011:组合模式(Composite Pattern)
- 深入浅出设计模式-012:状态模式(State Pattern)
- 学习swift缘由 swift学习网站汇总
- 深入分析Linux自旋锁
- Android&Mockito 模拟测试框架
- R的简单介绍
- mybatis-generator 源代码修改
- 深入浅出设计模式(1)
- L版本开机提示“Android正在升级或启动”
- web自动发送邮件
- Hibernate Tools使用说明
- F5刷新浏览器不缓存静态资源
- adb 详解下
- 视觉注意模型中的颜色特征划分
- Qt中SQLite3的增、删、改、查操作
- 内存对齐问题