Java设计模式,是一套由前人总结的,被反复使用的代码设计经验。它为我们解决一些实际问题提供了一些很好的设计模板,了解设计模式,有利于提高我们的代码设计能力,架构能力,更有可能自己能够设计出适合业务的一套设计模式。接下来就让我们了解一下这些神秘的设计模式。
总的来说,设计模式可以分为以下几大类。
创建型模式:
属于创建型模式的设计模式有单例模式,简单工厂模式,工厂方法模式,抽象工厂模式,原型模式,建造者模式。这些模式都是用来创建对象的,提供了方便的接口给客户端使用。创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展。
结构型模式:
属于结构型模式的设计模式有适配器模式,桥接模式,组合模式,装饰模式,外观模式,享元模式,代理模式。他们大多是用来组织某种结构,提供某种复杂的功能,不同的结构型模式关注如何将现有类或对象组织在一起形成更加强大的结构。比如适配器提供了将两个毫不相关的类或接口提供了桥梁,组合模式为树形结构提供了模板,外观模式为客户提供了方便简洁的接口,并且隐藏了内部细节。
行为型模式:
属于行为型模式的设计模式有职责链模式,命令模式,解释器模式,迭代器模式,中介者模式,备忘录模式,观察者模式,状态模式,策略模式,模板方法模式,访问者模式。这些模式为客户端提供了许多功能需求,注重对象之间的交互,关注他们之间的相互作用和职责划分。比如策略模式为用户提供了不同的策略选择,观察者模式,使得某个事件发生过后可以自动触发其他事件。又比如备忘录模式,使得用户可以恢复之前的某个状态,实现还原的功能。
接下来我们一个一个来看这些设计模式。
创造型模式
单例模式
需求:系统需要有一个恒定不变的对象,每次获取都是同一个对象。比如一个朝代只能有一个皇帝,一个公司只能有一个老板。那我们的系统就不能new出两个老板对象出来。windows系统的任务管理器便是实现了单例模式。
特点:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。而单例模式又分为两类,懒汉式和饿汉式。
饿汉式单例即一开始就new出一个实例,始终占据着内存,不管他以后是不是被用到。优点是不用考虑多线程的问题。
代码如下
public class EagerSingleton { privatestatic final EagerSingleton instance=new EagerSingleton(); privateEagerSingleton(){} publicstatic EagerSingleton getInstance(){ returninstance; } }
懒汉式单例即等到该对象第一次被使用时才new出一个实例,避免了一开始就占用资源。缺点是考虑多线程情况下同时new出多个实例的问题,需要使用锁,在多线程并发访问环境下会导致性能下降。
代码如下
public class LazySingleton { privatestatic LazySingleton instance=null; private LazySingleton(){} synchronizedpublic static LazySingleton getInsatance(){ if(instance==null)instance =new LazySingleton(); returninstance; } }
IoDH(Initializationon Demand Holder):即有延迟加载,又保证线程安全,不影响系统性能。缺点是与编程语言本身特性相关,java中可以实现,但很多面向对象语言不支持。
public class IoDH { privateIoDH(){} privatestatic class HolderClass{ privatefinal static IoDH instance =new IoDH(); } publicstatic IoDH getInsatance(){ returnHolderClass.instance; } }
简单工厂模式
需求:客户端想简单地传入不同参数就得到不同类的实例,不想很麻烦地一个一个去new。
特点:简单工厂针对抽象编程,使用static方法,根据传入的参数,new出对应的具体子类,用户可以通过Factory.Create(“对应参数”)得到对应实例,免除创建的职责。缺点是工厂类集中了大量创建代码,一旦不能正常工作整个系统都要受到影响。并且扩展十分困难,需要修改工厂逻辑。
示例代码如下:
abstract class Product { public void methodSame(){ //公共方法 } //抽象业务方法 public abstract void methodDiff(); } public class ConcreteProduct1 extends Product{ @Override public void methodDiff() { // TODO Auto-generated method stub System.out.println("我是第一号产品"); } } public class ConcreteProduct2 extends Product{ @Override public void methodDiff() { // TODO Auto-generated method stub System.out.println("我是第二号产品"); } } public class Factory { public static Product getProduct(String arg){ Product product =null; if(arg.equalsIgnoreCase("1")){ product=new ConcreteProduct1(); }else if(arg.equalsIgnoreCase("2")){ product=new ConcreteProduct2(); } return product; } } public class Client { public static void main(String[] args){ Product product1,product2; product1=Factory.getProduct("1"); product2=Factory.getProduct("2"); product1.methodDiff(); product2.methodDiff(); } }
工厂方法模式:
需求:同简单工厂模式。
特点:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。在简单工厂模式中,有加入新产品需要修改工厂逻辑的缺点,在工厂方法模式中,我们不再使用同一个工厂,而是不同的产品提供不同的工厂,每当我们加入新产品时,只需要实现新的工厂类,不用改变原来的任何一处代码。它缺点是新增一个产品类还要提供与之对应的工厂类,个数将成对增加。
代码结构:抽象产品类(或接口)作为抽象工厂类(或接口)的创建方法的参数传入,再通过具体的工厂实现类来得到对应的具体产品类。
抽象工厂模式:
需求:在日常生活中,每个产品都有不同的牌子,而同一个牌子旗下可能有不同的产品,怎么去模拟这样一个模式?
特点: 在简单工厂模式的基础上新增两个概念,分别是产品族和产品等级结构。产品等级结构即产品的继承结构,即抽象产品类/接口与它的实现类。产品族可以理解为一个品牌,相同品牌旗下的不同产品构成一个产品族。在抽象工厂模式中,一个产品族是由同一个工厂生产的。增加新的产品族只需要增加一个新的工厂,无需修改已有系统,符合开闭原则。但是,增加新的产品等级结构却需要较大的修改,这是它的缺点。