类设计原则及设计模式(一篇就够)

您所在的位置:网站首页 下定义的原则有哪些内容和特点 类设计原则及设计模式(一篇就够)

类设计原则及设计模式(一篇就够)

2024-04-02 23:32| 来源: 网络整理| 查看: 265

类设计原则及设计模式 类设计的六大原则设计模式定义设计模式的分类创建型模式1. 简单工厂和工厂方法模式定义和分类 2. 抽象工厂模式3. 单例模式定义优缺点饿汉式单例与懒汉式单例类比较代码实现 4. 建造者模式5. 原型模式 结构型模式适配器模式代理模式核心角色分类代理模式的应用场景代码实现 桥接模式桥接模式核心要点桥接模式总结桥接模式实际开发中应用场景代码实现 组合模式使用组合模式的场景组合模式的核心开发中的应用场景代码实现 装饰模式实现细节职责装饰器模式和桥接模式的区别代码实现 外观模式外观模式核心开发中常见的场景代码实现 享元模式场景核心享元模式实现享元模式开发中应用的场景代码实现 行为型模式策略模式场景本质开发中常见的场景代码实现 模版方法模式核心什么时候用到模版方法模式开发中常见的场景代码实现 观察者模式核心通知观察者的方式 开发中常见的场景代码实现 迭代子模式场景结构开发中常见的场景代码实现 责任链模式开发中常见的场景代码实现 命令模式结构开发中常见的场景代码实现 备忘录模式核心结构开发中常见的应用场景代码实现 状态模式场景结构开发中常见的场景代码实现 访问者模式模式动机:开发中的场景(应用范围非常少,了解即可) 中介者模式核心中介者模式的本质开发中常见的场景代码实现 解释器模式介绍开发中常见的场景 并发设计模式Furture模式生产者消费者模式 参考文献参考

类设计的六大原则

在阿里巴巴的设计规范中有提到类的设计原则,内容就是以下几点

开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。它是说我们在实现一个新功能时,首先应该想到的是扩展原来的功能,而不是修改之前的功能。 这个设计思想非常重要,也是一名优秀工程师所必备的设计思想。至于为什么要这样做?其实非常简单,我们团队在开发后端接口时遵循的也是这个理念。

随着软件越做越大,对应的客户端版本也越来越多,而这些客户端都是安装在用户的手机上。因此我们不能保证所有用户手中的 App(客户端)都一直是最新版本的,并且也不能每次都强制用户进行升级或者是协助用户去升级,那么我们在开发新功能时,就强制要求团队人员不允许直接修改原来的老接口,而是要在原有的接口上进行扩展升级。

因为直接修改老接口带来的隐患是老版本的 App 将不能使用,这显然不符合我们的要求。那么此时在老接口上进行扩展无疑是最好的解决方案,因为这样我们既可以满足新业务也不用担心新加的代码会影响到老版本的使用。

里氏代换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。接口隔离原则(Interface Segregation Principle) 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。迪米特法则(最少知道原则)(Demeter Principle) 为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。合成复用原则(Composite Reuse Principle) 原则是尽量使用合成/聚合的方式,而不是使用继承。 设计模式定义

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。本章系Java之美[从菜鸟到高手演变]系列之设计模式,我们会以理论与实践相结合的方式来进行本章的学习,希望广大程序爱好者,学好设计模式,做一个优秀的软件工程师!

23种模式java实现源码下载地址 http://pan.baidu.com/share/link?shareid=372668&uk=4076915866#dir/path=%2F%E5%AD%A6%E4%B9%A0%E6%96%87%E4%BB%B6

设计模式的分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下: 在这里插入图片描述 创建型模式

创建型模式是指提供了一种对象创建的功能,并把对象创建的过程进行封装隐藏,让使用者只关注具体的使用而并非对象的创建过程。它包含的设计模式有单例模式、工厂模式、抽象工厂模式、建造者模式及原型模式。

1. 简单工厂和工厂方法模式 定义和分类

工厂方法模式实现了创建者和调用者的分离。 详细分类:

简单工厂模式(静态工厂模式,对新增产品无能为力,不修改代码是无法扩展的)工厂方法模式(比静态工厂要好,扩展性比简单工厂模式好,但是增加类的维护)抽象工厂模式 工厂方法模式包含的角色: Product:抽象产品 ConcreteProduct:具体产品 Factory:抽象工厂 ConcreteFactory:具体工厂 说明:在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是把这个过程交给子类去做。从而更好地符合“开闭原则”。 应用举例:在实际开发中,一般将具体工厂类的实例化过程进行改进,不直接使用new 关键字来创建对象,而是将具体类的类名写入配置文件中,再通过java的反射机制,读取XML格式的配置文件,根据存储在XML文件中的类名字符串声称对象。 延伸:java反射(java reflection) 是指在程序运行时获取已知名称的类或已有对象的相关信息的一种机制,包括类的方法、属性、超类等信息。还包括实例的创建和实例类型的判断等等。可通过Class类的forName()方法返回与带有给定字符串名的类或者接口相关联的Class对象,再通过newInstance()方法创建此对象所表示的类的一个新实例。即:通过一个类名字符串得到类的实例。 Class c = Class.forName("String"); Object obj = c.newInstance(); return obj;

优点:完全符合“开闭原则"。 缺点:需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加。增加了系统的抽象性和理解难度。 使用情况: (1)一个类不知道它所需要的对象的类。 (2)一个类通过其子类来指定创建哪个对象。 (3)将创建的对象的任务委托给多个工厂子类中某一个。

2. 抽象工厂模式

模式动机: (1)多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。 (2)它是工厂模式中最为抽象和最具一般性的一种形态。 (3)工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。 抽象工厂模式包含的角色: AbstractFactory:抽象工厂 ConcreteFactory:具体工厂 AbstractProduct:抽象产品 Product:具体产品 优点: (1)抽象工厂模式隔离了具体类的生成,只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。 (2)可以实现高内聚低耦合的设计目的。 (3)增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。 缺点: (1)难以扩展抽象工厂来生产新种类的产品。 (2)开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦) 使用环境: (1)有多于一个的产品族。属于同一个产品族的产品将在一起使用。 (2)所有的产品以同样的接口出现。

3. 单例模式 定义

定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实。 单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 单例模式要点: (1)某个类只能有一个实例。 (2)它必须自行创建这个实例。 (3)它必须自行向整个系统提供这个实例。 模式分析: (1)单例类的构造函数为私有。 (2)提供一个自身的静态私有成员变量。 (3)提供一个公有的静态工厂方法。

优缺点

优点: (1)提供了对唯一实例的受控访问。 (2)可以节约系统资源。 (3)允许可变数目的实例。 缺点: (1)由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。 (2)单例类的职责过重,在一定程度上违背了“单一职责原则”。

单例模式的优点很明显,可以有效地节约内存,并提高对象的访问速度,同时避免重复创建和销毁对象所带来的性能消耗,尤其是对频繁创建和销毁对象的业务场景来说优势更明显。然而单例模式一般不会实现接口,因此它的扩展性不是很好,并且单例模式违背了单一职责原则,因为单例类在一个方法中既创建了类又提供类对象的复合操作,这样就违背了单一职责原则,这也是单例模式的缺点所在。

饿汉式单例与懒汉式单例类比较

饿汉式单例类在自己被加载时就将自己实例化。 (1)从资源利用,比懒汉式差。 (2)从速度和反应时间来讲,则比懒汉式稍微好些。 (3)懒汉式单例类在实例化时,必须处理好多个线程同时首次引用此类时的访问限制问题。 通过单例模式的学习告诉我们: 1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。 2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。 到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同? 首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的) 其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。 再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。 最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!

代码实现 package com.swad.designpattern.singleton; /** * Created by gonghaiyu on 13/02/2017. * 测试饿汉式单例模式 */ public class SingletonDemo1 { //加载类时,线程是安全的 private static SingletonDemo1 instance = new SingletonDemo1();//类初始化时立即加载 private SingletonDemo1(){ } //方法没有同步,效率高 public static SingletonDemo1 getInstance(){ return instance; } } package com.swad.designpattern.singleton; /** * Created by gonghaiyu on 13/02/2017. * 测试懒汉式单例模式 */ public class SingletonDemo2 { private static SingletonDemo2 instance; private SingletonDemo2(){} //方法同步调用效率低!synchronized 可以移动到函数内部,实现双重锁单例模式 public static synchronized SingletonDemo2 getInstance(){ if(instance==null){ instance = new SingletonDemo2(); } return instance; } } package com.swad.designpattern.singleton; /** * Created by gonghaiyu on 13/02/2017. * 测试静态内部类实现单例模式 * 这种方式:线程安全,调用效率高,并且实现类延迟加载! */ public class SingletonDemo4 { private static class SingletonClassInstance{ private static final SingletonDemo4 instance = new SingletonDemo4(); } private SingletonDemo4(){} public static SingletonDemo4 getInstance(){ return SingletonClassInstance.instance; } } package com.swad.designpattern.singleton; /** * Created by gonghaiyu on 13/02/2017. * 测试懒汉式单例模式(如何防止反射和凡序列化漏洞) */ public class SingletonDemo6 { private static SingletonDemo6 instance; private SingletonDemo6(){ if(instance!=null){ throw new RuntimeException(); } } //方法同步调用效率低!synchronized 可以移动到函数内部,实现双重锁单例模式 public static synchronized SingletonDemo6 getInstance(){ if(instance==null){ instance = new SingletonDemo6(); } return instance; } } package com.swad.designpattern.singleton; import java.lang.reflect.Constructor; /** * Created by gonghaiyu on 13/02/2017. */ public class Client2 { public static void main(String[] args) throws Exception{ SingletonDemo1 s1 = SingletonDemo1.getInstance(); SingletonDemo1 s2 = SingletonDemo1.getInstance(); System.out.println(s1); System.out.println(s2); Class clazz = (Class) Class.forName("com.swad.singleton.SingletonDemo6"); Constructor c = clazz.getDeclaredConstructor(null); c.setAccessible(true); SingletonDemo6 s3 =c.newInstance(); SingletonDemo6 s4 =c.newInstance(); System.out.println(s3); System.out.println(s4); } } 4. 建造者模式

模式动机:复杂对象相当于一辆有待建设的汽车,而对象的属性相当于汽车的部件。建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性已经它们的组装方式。 建造者模式的角色: Builder:抽象建造者 ConcreteBuilder:具体建造者 Director:指挥者 Product:产品角色 优点: (1)客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。 (2)新增的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,符合开闭原则。 缺点: (1)建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。 建设者模式与抽象工厂模式的比较: 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象。 工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码: 还和前面一样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类如下:

public class Builder { private List list = new ArrayList(); public void produceMailSender(int count) { for (int i = 0; i for (int i = 0; i public static void main(String[] args) { Builder builder = new Builder(); builder.produceMailSender(10); } }

从这点看出,建造者模式将很多功能集成到一个类里,这个类可以创造出比较复杂的东西。所以与工程模式的区别就是:工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分。因此,是选择工厂模式还是建造者模式,依实际情况而定。

5. 原型模式

(1)提供的Ctrl+C与Ctrl+V操作就是原型模式的应用,复制得到的对象与原型对象是两个类型但是内存地址不同的对象,通过原型模式可以大大提高对象的创建效率。 (2)在Struts2中为了保证线程的安全性,Action对象的创建使用了原型模式。访问一个已经存在的Action对象时将通过克隆的方式创建出一个新的对象,从而保证其中定义的变量无须进行加锁实现同步,每一个Action中都有自己的成员变量,避免Struts1因使用单例模式而导致的并发和同步问题。 (3)Spring中,也采用原型模式来创建新的bean实例。 原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。本小结会通过对象的复制,进行讲解。在Java中,复制对象是通过clone()实现的,先创建一个原型类:

public class Prototype implements Cloneable { public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone(); return proto; } }

很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,我会在另一篇文章中,关于解读Java中本地方法的调用,此处不再深究。在这儿,我将结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念: 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。 此处,写一个深浅复制的例子:

public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String string; private SerializableObject obj; /* 浅复制 */ public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone(); return proto; } /* 深复制 */ public Object deepClone() throws IOException, ClassNotFoundException { /* 写入当前对象的二进制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); /* 读出二进制流产生的新对象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public String getString() { return string; } public void setString(String string) { this.string = string; } public SerializableObject getObj() { return obj; } public void setObj(SerializableObject obj) { this.obj = obj; } } class SerializableObject implements Serializable { private static final long serialVersionUID = 1L; }

要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。 但需要注意的是,以上代码为浅克隆的实现方式,如果要实现深克隆(对所有属性无论是基本类型还是引用类型的克隆)可以通过以下手段实现:

所有对象都实现克隆方法;通过构造方法实现深克隆;使用 JDK 自带的字节流实现深克隆;使用第三方工具实现深克隆,比如 Apache Commons Lang;使用 JSON 工具类实现深克隆,比如 Gson、FastJSON 等。 结构型模式

结构型模式关注的是对象的结构,它是使用组合的方式将类结合起来,从而可以用它来实现新的功能。 7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,我们看下面的图: 在这里插入图片描述

适配器模式

适配器模式 将一份类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能在一起工作。

模式中的角色 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可是接口。 需要适配的类(Adaptee):需要适配的类或适配者类。 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换为目标接口。

分类 主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。 类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

工作场景 3.1 经常用来做旧系统改造和升级 3.2 如果我们的系统开发之后再也不需要维护,那么很多模式都是没有必要的,但是不幸的是,事实却是维护一个系统的代价往往是开发一个系统的数倍。 我们学习中见过的场景 1.java.io.InputStreamReader(InputStream) 2.java.io.OutputStreamWriter(OutputStream) 3.JDBC给出了一个客户端通用的抽象接口,每一个具体数据引擎的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件。 4.在Spring AOP框架中,对BeforeAdvice,AfterAdvice,ThrowsAdvice三种通知类借助于适配器来实现。

代码实现

package com.swad.designpattern.adapter; public interface Target { void handleReq(); } package com.swad.designpattern.adapter; /** * 被适配的类 * @author gonghaiyu * */ public class Adaptee { public void request(){ System.out.println("可以完成客户需要的功能!"); } } package com.swad.designpattern.adapter; /** * 适配器本身(类适配器方式,对象组合的方式) * @author gonghaiyu * */ public class Adapter extends Adaptee implements Target{ @Override public void handleReq() { super.request(); } } package com.swad.designpattern.adapter; public class Adapter2 implements Target{ private Adaptee adaptee; @Override public void handleReq() { adaptee.request(); } public Adapter2(Adaptee adaptee) { super(); this.adaptee = adaptee; } } package com.swad.designpattern.adapter; /** * 客户端类 * (相当于例子中的笔记本,只有usb接口) * @author gonghaiyu * */ public class Client { public void test1(Target t){ t.handleReq(); } public static void main(String[] args){ Client c = new Client(); Adaptee a = new Adaptee(); //1.第一种方式采用类适配器的方式 // Target t =new Adapter(); //2.第二种方式采用组合的方式 Target t = new Adapter2(a); c.test1(t); } } 代理模式 核心角色 1.抽象角色 定义代理角色和真是角色的公共对外方法 2.真实角色 实现抽象角色、定义真实角色所要实现的业务逻辑,供代理角色调用。 3.代理角色 实现抽象角色,是真是角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制放到代理角色中处理! 分类

静态代理:(代码写死的代理类) 动态代理:(动态生成代理类,代码自动生成代理类) 1.JDK自带的动态代理 2.javaassist字节码操作库实现 3.CGLIB 4.ASM(底层使用指令,可维护性较差)

动态代理: JDK自带的动态代理 1.java.lang.reflect.Proxy 作用:动态生成代理类和对象 2.java.lang.reflect.InvocationHandler(处理器接口) 2.1可以通过invoke方法实现对真实角色的代理访问。 2.2每次通过Proxy生成代理类对象时都要指定对应的处理器对象

代理模式的应用场景

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。 2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。 使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

代码实现 静态代理 package com.swad.designpattern.proxy.staticProxy; public interface Star { /** * 面谈 */ void confer(); /** * 签合同 */ void signContract(); /** * 订票 */ void bookTicket(); /** * 唱歌 */ void sing(); /** * 收钱 */ void collectMoney(); } package com.swad.designpattern.proxy.staticProxy; public class RealStar implements Star{ @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.signContract()"); } @Override public void bookTicket() { System.out.println("RealStar.bookTicket()"); } @Override public void sing() { System.out.println("RealStar(Joy).sing()"); } @Override public void collectMoney() { System.out.println("RealStar.collectMoney()"); } } package com.swad.designpattern.proxy.staticProxy; public class ProxyStar implements Star{ private Star star; public ProxyStar(Star star) { super(); this.star = star; } @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.signContract()"); } @Override public void bookTicket() { System.out.println("RealStar.bookTicket()"); } @Override public void sing() { star.sing(); } @Override public void collectMoney() { System.out.println("RealStar.collectMoney()"); } } package com.swad.designpattern.proxy.staticProxy; public class Client { public static void main(String[] args) { Star real = new RealStar(); Star proxy = new ProxyStar(real); proxy.confer(); proxy.signContract(); proxy.bookTicket(); proxy.sing(); proxy.collectMoney(); } } 动态代理 package com.swad.designpattern.proxy.dynamicProxy; public interface Star { /** * 面谈 */ void confer(); /** * 签合同 */ void signContract(); /** * 订票 */ void bookTicket(); /** * 唱歌 */ void sing(); /** * 收钱 */ void collectMoney(); } package com.swad.designpattern.proxy.dynamicProxy; public class RealStar implements Star{ @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.signContract()"); } @Override public void bookTicket() { System.out.println("RealStar.bookTicket()"); } @Override public void sing() { System.out.println("RealStar(Joy).sing()"); } @Override public void collectMoney() { System.out.println("RealStar.collectMoney()"); } } package com.swad.designpattern.proxy.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class StarHandler implements InvocationHandler{ Star realStar; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("+++++++"); //可以统一处理其他 method.invoke(realStar, args); return null; } public StarHandler(Star realStar) { super(); this.realStar = realStar; } } package com.swad.designpattern.proxy.dynamicProxy; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { Star real = new RealStar(); StarHandler handler = new StarHandler(real); Star proxy = (Star)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler); proxy.bookTicket(); proxy.sing(); } } 桥接模式

桥接模式:就像一座桥,将两个变化维度连接起来,各个维度都可以独立的变化。故称:桥接模式。问题由商品分类问题引入。

桥接模式核心要点

处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。

桥接模式总结 桥接模式可以取代多层继承的方案。多层继承违背了单一职责原则,复用性较差,类的个数也非常多。桥接模式可以极大的减少子类的个数,从而降低管理和维护成本。桥接模式极大的提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有的系统,符合开闭原则。 桥接模式实际开发中应用场景

-JDBC驱动程序

AWT中的Peer架构 -银行日志管理: 格式分类:操作日志、交易日志、异常日志 距离分类:本地记录日志、异地记录日志 -人力资源系统中的奖金计算模块: 奖金分类:个人奖金、团体奖金、激励奖金 部门分类:人事部门、销售部门、研发部门 -OA系统中的消息处理: 业务类型:普通消息、加急消息、特急消息 发送消息方式:系统内消息、手机短信、邮件 代码实现 package com.swad.designpattern.proxy.bridge; public class Computer { protected Brand brand; public Computer(Brand b){ this.brand = b; } public void sale(){ brand.sale(); } } class Desktop extends Computer{ public Desktop(Brand b){ super(b); } public void sale(){ super.sale(); System.out.println("销售台式机"); } } class Laptop extends Computer{ public Laptop(Brand b){ super(b); } public void sale(){ super.sale(); System.out.println("销售笔记本"); } } package com.swad.designpattern.proxy.bridge; public interface Brand { void sale(); } class Lenovo implements Brand{ @Override public void sale() { System.out.println("销售联想电脑"); } } class Dell implements Brand{ @Override public void sale() { System.out.println("销售Dell电脑"); } } package com.swad.designpattern.proxy.bridge; public class Client { public static void main(String[] args) { //销售联想笔记本电脑 Computer c = new Laptop(new Lenovo()); c.sale(); } } 组合模式 使用组合模式的场景

把部分和整体的关系用树形结构来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象。

组合模式的核心

抽象构件(Component)角色:定义了叶子和容器构件的共同点叶子(Leaf)构件角色:无子节点容器(Composite)构件角色:有容器特征,可以包含子节点。

开发中的应用场景

-操作系统的资源管理器 -GUI中的容器层次图 -XML文件解析 -OA系统中,组织结构的处理 -Junit单元测试框架 -将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。

代码实现 package com.swad.designpattern.composite; import java.util.ArrayList; import java.util.List; //抽象构件 public interface AbstractFile { void killVirus();//杀毒 } class ImageFile implements AbstractFile{ private String name; public ImageFile(String name){ super(); this.name = name; } @Override public void killVirus() { System.out.println("--图像文件杀毒--"+name+",进行查杀!"); } } class TextFile implements AbstractFile{ private String name; public TextFile(String name){ super(); this.name = name; } @Override public void killVirus() { System.out.println("--文


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3