ps:本文系为转载,阅读原文可获取源码,文章末尾有原文连接java
ps:这一篇是写建造者模式、原型模式和适配器模式ide
**一、建造者模式
**测试
指将一个复杂对象的构造与它的表示分离,使一样的构建过程能够建立不一样的表示;它是将一个复杂的对象分解为多个简单的对象,而后一步一步构建而成;建造者模式注重零部件的组装过程。ui
建造者模式由如下几个角色组成:this
(1)产品角色:它是一个复杂对象,包含多个组成部件,由具体建造者来建立其各个零部件。spa
(2)抽象建造者:它是一个包含建立产品每一个部件的抽象方法的抽象类,通常还提供返回复杂产品的方法。指针
(3)具体建造者:它是抽象建造者的子类,完成复杂产品的各个部件的具体建造方法。日志
(4)指挥者:它调用建造者对象中的部件构造和组装方法完成复杂对象的建造,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。code
产品角色,新建一个产品类 AirShip,它包含 OrbitalModel、Engine engine 和 EscapeTower 这几个部件;orm
public class AirShip { private OrbitalModel orbitalModel; private Engine engine; private EscapeTower escapeTower; public OrbitalModel getOrbitalModel() { return orbitalModel; } public void setOrbitalModel(OrbitalModel orbitalModel) { this.orbitalModel = orbitalModel; } public Engine getEngine() { return engine; } public void setEngine(Engine engine) { this.engine = engine; } public EscapeTower getEscapeTower() { return escapeTower; } public void setEscapeTower(EscapeTower escapeTower) { this.escapeTower = escapeTower; } } class OrbitalModel { private String name; public OrbitalModel(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Engine { private String name; public Engine(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class EscapeTower { private String name; public EscapeTower(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
抽象建造者,新建一个 AirShipBuilder 接口,包含建立 OrbitalModel、Engine engine 和 EscapeTower 这几个部件的抽象方法;
public interface AirShipBuilder { public OrbitalModel builderOrbitalModel(); public Engine builderEngine(); public EscapeTower builderEscapeTower(); }
具体建造者,新建一个类 MyAirShipBuilder 并实现 AirShipBuilder;
public class MyAirShipBuilder implements AirShipBuilder{ @Override public OrbitalModel builderOrbitalModel() { System.out.println("轨道舱"); return new OrbitalModel("个人轨道舱"); } @Override public Engine builderEngine() { System.out.println("发动机"); return new Engine("个人发动机"); } @Override public EscapeTower builderEscapeTower() { System.out.println("逃逸塔"); return new EscapeTower("个人逃逸塔"); } }
指挥者,新建一个类 MyAirShipDirector 并实现 AirShipDirector 接口,在当前类中用 directorAirShip 方法建造部件和组装产品;
public interface AirShipDirector { public AirShip directorAirShip(); }
public class MyAirShipDirector implements AirShipDirector{ private AirShipBuilder builder; public MyAirShipDirector(AirShipBuilder builder) { super(); this.builder = builder; } @Override public AirShip directorAirShip() { Engine engine = builder.builderEngine(); OrbitalModel orbitalModel = builder.builderOrbitalModel(); EscapeTower escapeTower = builder.builderEscapeTower(); AirShip airShip = new AirShip(); airShip.setEngine(engine); airShip.setEscapeTower(escapeTower); airShip.setOrbitalModel(orbitalModel); return airShip; } }
在客户端测试
AirShipDirector director = new MyAirShipDirector(new MyAirShipBuilder()); AirShip airShip = director.directorAirShip(); System.out.println(airShip.getEngine().getName()); System.out.println(airShip.getEscapeTower().getName()); System.out.println(airShip.getOrbitalModel().getName());
建造者模式封装性好,扩展性好,每一个建造者相互独立互补影响,便于解耦;在调用客户端端时没必要理会产品内部组成的细节,可是建造的部件和产品内部的部件必须相同,限制了建造的范围;若是产品内部部件发生变化,那么建造者也须要跟着更改。
二、原型模式
用一个已经存在的实例做为原型,建立一个和原型相同类型的对象不须要 new,经过复制该原型对象就能够建立一个和原型类似的新对象;这里的原型对象和新对象不是同一个对象,而是它们同属一个类。
原型模式有如下角色:
(1)抽象原型类:具体原型对象必须实现的接口 Cloneable。
(2)具体原型类:实现抽象原型类的 clone() 方法,返回一个被复制的对象。
(3)访问类:也就是客户端类调用具体原型类中的 clone() 方法来完成新的对象拷贝。
原型模式的克隆划分为浅克隆和深克隆;浅克隆就是对象的 clone 方法只会复制对象属性中的基本的数据类型(8种基本数据类型),不会复制非基本的数据类型,非基本的数据类型仍是指向原型对象属性的内存地址;深克隆就是把非基本数据类型的属性也给复制过去,非基本数据类型的对象再也不指向原型对象的属性地址;下面对2种克隆进行举例;
二、1 浅克隆
因为我是用 Java 代码写的,而 Java 没有对指针进行扩展,因此这个基本数据类型很差验证,咱们就验证上面所说的非基本的数据类型仍是指向原型对象属性的内存地址。
(1)抽象原型类,它是 Cloneable 接口,Java 内部提供,不用本身去新写:
package java.lang; public interface Cloneable { }
(2)具体原型类,新建一个 Sheep 类并实现 Cloneable 接口:
public class Sheep implements Cloneable{ private String name; private Date birthday; public Sheep() { System.out.println("Sheep类对象无参构造方法"); } public Sheep(String name, Date birthday) { super(); this.name = name; this.birthday = birthday; System.out.println("Sheep类对象有2个参数的构造方法"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public Object clone() throws CloneNotSupportedException { Object object = super.clone(); return object; } }
(3)客户端类,新建一个 Test 类,对 Sheep 类的原型对象进行克隆:
public class Test { public static void main(String[] args) { Date date = new Date(12345689l); String objectString = "原型对象----"; String objectString2 = "新对象----"; Sheep s1 = new Sheep("多利",date); System.out.println(objectString + s1); System.out.println(objectString + s1.getName()); System.out.println(objectString + s1.getBirthday()); System.out.println("________________________________"); try { Sheep s2 = (Sheep) s1.clone(); date.setTime(345466578887l); System.out.println(objectString2 + s2); System.out.println(objectString2 + s2.getName()); System.out.println(objectString2 + s2.getBirthday()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
日志打印以下所示:
从日志能够看出,原型对象和新对象不是同一个对象,当咱们把原型对象克隆给新对象以后,再更改原型对象的属性 date 的内容,发现新对象的属性 date 内容也更改了,这就论证了上面说的,浅克隆不会复制非基本的数据类型。
二、2 深克隆
咱们来验证非基本数据类型的对象再也不指向原型对象的属性地址这句话。
(1)在上面浅克隆代码的基础上,咱们把 Sheep 类的 clone 方法修改一下,其余的不变:
@Override public Object clone() throws CloneNotSupportedException { Object object = super.clone(); Sheep sheep = (Sheep) object; sheep.birthday = (Date) this.birthday.clone(); return object; }
(2)客户端类不变,仍是和浅克隆的示例同样调用:
Date date = new Date(12345689l); String objectString = "原型对象----"; String objectString2 = "新对象----"; Sheep s1 = new Sheep("多利",date); System.out.println(objectString + s1); System.out.println(objectString + s1.getName()); System.out.println(objectString + s1.getBirthday()); System.out.println("________________________________"); try { Sheep s2 = (Sheep) s1.clone(); date.setTime(345466578887l); System.out.println(objectString2 + s2); System.out.println(objectString2 + s2.getName()); System.out.println(objectString2 + s2.getBirthday()); } catch (CloneNotSupportedException e) { e.printStackTrace(); }
日志打印以下:
客户端这边先对原型对象进行克隆获得新对象,而后再改变原型对象 date 的内容,再输出新对象的信息,发现新对象的 date 内容和原型对象刚初始化 date 内容同样,说明了深克隆实现了非基本数据类型的对象再也不指向原型对象的属性地址。
使用深克隆方式保存对象的状态,使用原型模式拷贝,将其状态保存起来,简化了建立对象的过程;每一个被克隆的类必须实现 Cloneable 接口并重写 clone 方法,从2个克隆的案例中能够看出,使用原型模式拷贝对象不会调用类的构造方法,由于是经过调用 Object 类的 clone 方法实现的;原型模式和单例模式一块儿用,单例模式就会失效,由于访问权限 private 都对原型模式无效。
**三、适配器模式
**
将一个类的接口转换成客户指望的另外一个接口,它使得本来由于接口不兼容、不能一块儿工做的一些类能够在一块儿工做。
适配器模式有如下角色:
(1)目标接口:客户所期待的接口,目标能够是抽象类,也能够是接口,目标接口的实现类会使用接口方法调用适配者。
(2)适配者:它是被调用和适配的现存组件库中的组件接口。
(3)适配器:它是一个转换器,实现了目标接口,经过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户用目标接口来调用适配者。
适配器模式可分为类适配器模式和对象适配器模式,类适配器模式就是适配器继承适配者,用接口方法调用适配器继承适配者过来的方法;对象适配器模式就是采用对象组合方式实现,适配器和适配者不存在关系,用接口方法调用适配者的方法。
**三、1 类适配器模式
**
(1)目标接口,新建一个接口 TargetInterface:
public interface TargetInterface { public void request(); }
(2)适配者,新建一个类 AdapteeClass:
public class AdapteeClass { public void performRequest() { System.out.println("适配者的performRequest方法被执行"); } }
(3)适配器,新建一个类 AdapterClass,继承 AdapteeClass 并实现 TargetInterface 接口:
public class AdapterClass extends AdapteeClass implements TargetInterface{ @Override public void request() { performRequest(); } }
(4)在客户端进行调用:
TargetInterface targetInterface = new AdapterClass(); targetInterface.request();
**三、2 对象适配器模式
**
(1)在类适配器模式的状况下,咱们再也不新建目标接口和适配者,这里新建另一个适配器,类名叫 Adapter2Class 并实现目标接口 TargetInterface:
public class Adapter2Class implements TargetInterface{ private AdapteeClass adapteeClass; public Adapter2Class(AdapteeClass adapteeClass) { this.adapteeClass = adapteeClass; } @Override public void request() { adapteeClass.performRequest(); } }
(2)在客户端进行调用:
AdapteeClass adapteeClass = new AdapteeClass(); TargetInterface targetInterface = new Adapter2Class(adapteeClass); targetInterface.request();
对象适配器模式中的适配器拥有一个适配者对象的属性,把这个具体的特殊功能委托给适配者对象来实现;使用对象适配器模式,可使得适配器根据传入的适配者对象或者适配者子类对象达到适配多个不一样被适配的功能;不论是类适配器模式仍是对象适配器模式,它具备灵活性,只需修改适配器类和客户端的代码就能够了。
对于对象适配器来讲,更换适配器的实现过程不简单;对于类适配器来讲,比较单一,一个适配器只能有一个适配者;经过适配器,客户端能够调用同一接口,对客户端来讲是透明的;类适配者复用了现存的类,开发者不须要修改原有代码而重用现有的适配者类;将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题,就比如插座口和手机充电口插头。