设计模式分类
总体来说设计模式分为三大类:
创建型模式:
单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
结构型模式:
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式:
策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式思维导图
单例模式
单例模式的八种写法
1、饿汉式(静态常量)[可用]
2、饿汉式(静态代码块)[可用]
3、懒汉式(线程不安全)[不可用]
4、懒汉式(线程安全,同步方法)[不推荐用]
5、懒汉式(线程安全,同步代码块)[不可用]
6、双重检查[推荐用]
7、静态内部类[推荐用]
8、枚举[推荐用]
简单工厂
又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。
工厂方法模式
public abstract class AbstractDriverFactory { public abstract Animal createDriver();//这个方法是为了它的子类重写它的构造方法 } public class ZhangFactory extends AbstractDriverFactory { @Override public Driver createDriver() { return new Zhang();//返回一个具体的对象老张。 } } public static void main(String[] args) { ZhangFactory zf = new ZhangFactory();//创建老张的工厂对象 Driver driver = zf.createDriver();//再调用创建司机的方法 driver.driveCar();//司机去开车 }
不得不说,工厂方法模式虽然完美符合了ocp开闭原则(Open Closed Principle)原则,但却使整个程序变得很沉重。就拿数据库来说,如果有100个访问数据库的类,那么就要创建100个这个类的工厂。
1.简单工厂模式:最大的优点就是在工厂中就包含了必要的判断,使用时只需要根据客户端的选择来实例化即可,对于客户端使用来说,去除了与具体产品的依赖。而缺点就是违背的ocp原则。假如未来要添加一个新的需求,则需要更改简单工厂中的判断语句。这对代码本身就不利。
2.工厂方法模式:最大的优点就是抽象化了简单工厂模式。再有新的需求进来时,不需要更改工厂的内容,符合了ocp原则。而缺点是每增加一个产品就要新增加一个相应的实例化工厂,增加了额外的开发量。
3.抽象工厂模式:分离了具体的类。不会出现在客户端代码中,易于交换产品系列。而且具体的工厂类只在它初始化的时候才会出现。这使得改变一个应用的具体工厂变得很容易~~缺点是,抽象工厂几乎确定了可以创建的对象的集合。加入新的类型对象就需要扩展其接口,这将涉及到具体工厂及其子类的修改。
三种工厂模式虽然用法各不相同,但它们的最终目的都是一致的----解耦。spring容器就是个大型的抽象工厂,不仅可以创建普通的bean实例,也可以创建bean工厂。
适配器模式
将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作,说白了就是为了挂羊头卖狗肉而专门设计的模式。也就是把一个类的接口变换成客户端所期待的另一种接口。
1 ,类的适配
(1)目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类。
(2)源(Adapee)角色:现在需要适配的接口。
(3)适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。
2, 对象的适配
对象的适配依赖于对象的组合,而不是类适配中的继承。
还是以手机为例子,每一种机型都自带有从电器,有一天自带充电器坏了,而且市场没有这类型充电器可买了,怎么办?万能充电器就可以解决,这个万能充电器就是适配器。
首先来一个IPhone的充电器类(Adaptee角色):
public class IPhoneCharger { public void applePhoneCharge(){ System.out.println("The iPhone is charging ..."); } }
要对这个特殊的充电器进行适配,上个适配的接口(Target角色):
public interface ChargeAdapter { public void phoneCharge(); }
因为适配有两种,所以先进行类的适配示例,创建类的适配器:
public class UniversalCharger extends IPhoneCharger implements ChargeAdapter{ @Override public void phoneCharge() { System.out.println("The phone is charging, but which kind of phone it is, who cares ..."); super.applePhoneCharge();//iphone charging } }
这就是万能充电器了,我们让它来充个电,测试类准备:
public class AdapterClassTest { public static void main(String[] args) { ChargeAdapter charger = new UniversalCharger(); charger.phoneCharge(); } }
测试结果:
The phone is charging, but which kind of phone it is, who cares ... The iPhone is charging ...
以上是类的适配,我们还有种对象的适配方式,创建对象的适配器:
public class UniversalCharger implements ChargeAdapter{ IPhoneCharger iphoneCharger; public UniversalCharger(IPhoneCharger iphoneCharger){ this.iphoneCharger = iphoneCharger; } @Override public void phoneCharge() { System.out.println("The phone is charging, but which kind of phone it is, who cares ..."); iphoneCharger.applePhoneCharge(); } }
对象适配器创建完毕,测一下:
public class AdapterObjectTest { public static void main(String[] args) { IPhoneCharger iphoneCharger = new IPhoneCharger(); ChargeAdapter charger = new UniversalCharger(iphoneCharger); charger.phoneCharge(); } }
测试结果:
The phone is charging, but which kind of phone it is, who cares ... The iPhone is charging ...
总结一下:
(1)类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
(2)对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个包装类,持有原类的一个实例,在包装类的方法中,调用实例的方法就行。