设计模式:一套被反复使用的、代码设计经验的总结,使用设计模式是为了让代码能够重用,使得被他人易理解,保证代码的可靠性。
设计模式的六大原则:
1、开闭原则(Open Close Principal):对扩展开放,对修改关闭,为了使程序的扩展性好,易于代码的维护和升级,例如接口和抽象类的使用
2、里氏代换原则:任何基类出现的地方,子类一定可以替换
3、依赖倒转原则:针对接口编程,依赖于抽象而不依赖具体。
4、接口隔离原则:使用多个隔离的接口,比使用单个接口要好
5、最少知道原则:一个实体应当尽量少于其它实体之间发生作用,使系统模块相对独立
6、合成复用原则:尽量使用合成/聚会的方式,而不是使用继承
创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
创建型模式:使对象的创建和使用分离
1、单例模式
public class Singleton {
//延迟加载
private static Singleton singleton=null;
//私有化构造方法,防止被实例化
private Singleton(){}
public static Singleton getSingleton()
{
if(singleton==null)
{
instance = new Singleton();
}
return singleton;
}
}
优化:
public class Singleton {
private Singleton(){}
private static class SingletonFactorn{
private static Singleton singleton=new Singleton();
}
private static Singleton getSingleton()
{
return SingletonFactorn.singleton;
}
}
2、工厂模式
2.1 普通工厂模式
2.2 多工厂模式
2.3 静态工厂模式
package chuangjian.FactoryMethod;
//工厂类
public class SendFactory {
/*
* 普通工厂模式*/
public Sender produce(String type)
{
if("mail".equals(type))
{
return new MailSender();
}
else if("sms".equals(type))
{
return new SmsSender();
}
else
{
System.out.println("请输入正确类型");
return null;
}
}
/*
* 是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,
* 则不能正确创建对象,
* 而多个工厂方法模式是提供多个工厂方法,分别创建对象*/
public Sender produceMail()
{
return new MailSender();
}
public Sender produceSms()
{
return new SmsSender();
}
}
package chuangjian.FactoryMethod;
public class FactoryTest {
public static void main(String[] args) {
/* 普通工厂测试
SendFactory sendFactory=new SendFactory();
Sender sender=sendFactory.produce("mail");
sender.send();*/
//多工厂模式测试
SendFactory sendFactory=new SendFactory();
Sender sender=sendFactory.produceMail();
sender.send();
}
}
总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
好处:客户端不需要创建对象,明确了各个类的职责
缺点:该工厂类负责创建所有实例,如果有新的类加入,需要不断的修改工厂类,不利于后期的维护
3、抽象工厂模式
在工厂模式的基础上添加一个接口,如果需要添加新的功能,不需要改变原有代码,创建一个类实现Send接口,一个工厂类实现provider接口
好处:如果有新的类进来,只需要添加一个对应的具体工厂类,不影响现有代码,增加了程序的扩展性
缺点:增加了代码量
4、建造者模式
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性
5、原型模式
该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象
结构型模式:如何将类或对象按某种布局组成更多的结构
1、适配器模式
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。
类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。
2、装饰模式
装饰模式就是给一个对象添加一些新的功能,而且是动态变化的,装饰对象和被装饰对象实现同一个接口,装饰对象包括被装饰对象的实例
装饰器模式的应用场景:
1、需要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
缺点:产生过多相似的对象,不易排错!
3、代理模式
代理(Proxy)模式:为某对象提供一种代理以
控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
4、外观模式
外观模式是为了解决类与类之家的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口
如果我们没有Computer类,那么,CPU、Memory、Disk他们之间将会相互持有实例,产生关系,这样会造成严重的依赖,修改一个类,可能会带来其他类的修改,这不是我们想要看到的,有了Computer类,他们之间的关系被放在了Computer类里,这样就起到了解耦的作用,这就是外观模式!
5、桥接模式
将抽象化和实现化解耦,使二者可以独立变化
例如JDBC桥DriverManager,JDBC在进行数据库连接时,当需要切换不同的数据库时,无需改变太多代码,因为JDBC提供了统一的接口,每个数据库各自实现,然后调用数据库驱动的程序来桥接就可以了
6、组合模式
组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便
使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数
7、享元模式
享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。
适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量
通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能
行为型模式:用于描述类和对象之间如何相互协作完成单个对象无法完成的任务,以及如何分配任务。
1、策略模式
策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数.
策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可
2、模板方法模式
模板方法模式:定义一个操作算法骨架,将算法的一些步骤延迟到子类中,使得子类可以不该
变算法骨架的情况下重新定义该算法的一些步骤,即一个抽象类,主方法调用一些方法,可以是抽线或者实现的
再定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用
3、观察者模式
多个对象间存在一对多关系,当一个对象发生改变时,会把这种改变通知给其他多个对象,从而影响其他对象的行为
4、迭代器模式
迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。这句话包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问
5、责任链模式
职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整
此处强调一点就是,链接上的请求可以是一条链,可以是一个树,还可以是一个环,模式本身不约束这个,需要我们自己去实现,同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象
6、命令模式
命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。
7、备忘录
备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它
8、状态模式
状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。比如QQ来说,有几种状态,在线、隐身、忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:1、可以通过改变状态来获得不同的行为。2、你的好友能同时看到你的变化
9、访问者模式
该模式适用场景:如果我们想为一个现有的类增加新功能,不得不考虑几个事情:
新功能会不会与现有功能出现兼容性问题?
以后会不会再需要添加?
如果类不允许修改代码怎么办?
面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦。
10、中介者模式
中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。如果使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行,这有点像spring容器的作用
11、解释器模式
解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。一般主要应用在OOP开发中的编译器的开发中,所以适用面比较窄。