您的位置:首页 > 编程语言 > Java开发

JAVA基础9(设计模式 单例模式 工厂模式 建造者模式 原型模式)

2015-08-25 20:36 676 查看
创建型模式(新建对象): 单例模式 工厂模式 抽象工厂模式 建造者模式 原型模式

结构型模式: 适配器模式 桥接模式 装饰模式 组合模式 外观模式 享元模式 代理模式

行为型模式: 模板方法模式 命令模式 迭代器模式 观察者模式 中介者模式 备忘录模式 解释器模式 状态模式 策略模式 职责链模式 访问者模式

单例模式: 保证一个类只有一个实例 并且提供一个访问该实例的全局访问点

常见的五种单例模d式实现方式:

主要:饿汉式 (线程安全 调用效率高 但是 不能延时加载)

懒汉式 (线程安全 调用效率不高 但是 可以延时加载)

其他: 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题, 不建议使用)

静态内部类式( 线程安全,调用效率高 但是可以延时加载)

枚举单例(线程安全 调用效率高 不能延时加载)

如何使用?

单例对象 占用资源少 不需要 延时加载:

枚举式 好于饿汉式

单例对象 占用资源大 需要延时加载

静态内部类式 好于 懒汉式

案例:测试饿汉式单例模式

<span style="font-size:14px;">public class SingletonDemo1 {
//类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的!
private static SingletonDemo1 instance = new SingletonDemo1();
private SingletonDemo1(){
}
//方法没有同步,调用效率高!
public static SingletonDemo1  getInstance(){
return instance;
}
}</span>


案例: 测试懒汉式单例模式

<span style="font-size:14px;">public class SingletonDemo2 {
//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
private static SingletonDemo2 instance;
private SingletonDemo2(){ //私有化构造器
}
//方法同步,调用效率低! 资源利用率高了 但是并发得同步
public static  synchronized SingletonDemo2  getInstance(){
if(instance==null){
instance = new SingletonDemo2();
}
return instance;
}
}</span>


案例: 双重检测锁实现

偶后会出问题 不建议使用

<span style="font-size:14px;">public class SingletonDemo3 {
private static SingletonDemo3 instance = null;
public static SingletonDemo3 getInstance() {
if (instance == null) {
SingletonDemo3 sc;
synchronized (SingletonDemo3.class) {
sc = instance;
if (sc == null) {
synchronized (SingletonDemo3.class) {
if(sc == null) {
sc = new SingletonDemo3();
}
}
instance = sc;
}
}
}
return instance;
}
private SingletonDemo3() {
}
}</span>


案例 静态内部类的单例模式

<span style="font-size:14px;">外部类木有static属性, 则不会像饿汉式那样立即加载对象
只有真正调用getInstance(),才会加载内部类,加载类时是线程安全的, instance 是static final类型,保证了内存中只有一个实例存在,而且只能被赋值一次,从而保证了线程安全
兼备了并发高校调用和延迟加载的优势

/**
* 测试静态内部类实现单例模式
* 这种方式:线程安全,调用效率高,并且实现了延时加载!
* @author 尚学堂高淇 www.sxt.cn
*
*/
public class SingletonDemo4 {
private static class SingletonClassInstance {
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4(){
}
//方法没有同步,调用效率高!
public static SingletonDemo4  getInstance(){
return SingletonClassInstance.instance;
}
}</span>


案例 枚举式实现单例模式(没有延时加载)

<span style="font-size:14px;">public enum SingletonDemo5 {
//这个枚举元素,本身就是单例对象!
INSTANCE;
//添加自己需要的操作!
public void singletonOperation(){
}
}</span>


案例 测试懒汉式单例模式(如何防止反射和反序列化漏洞)

<span style="font-size:14px;">public class SingletonDemo6 implements Serializable {
//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
private static SingletonDemo6 instance;

private SingletonDemo6(){ //私有化构造器
//以下代码 防止 反射 来创建对象
if(instance!=null){
throw new RuntimeException();
}
}

//方法同步,调用效率低!
public static  synchronized SingletonDemo6  getInstance(){
if(instance==null){
instance = new SingletonDemo6();
}
return instance;
}
//反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!
private Object readResolve() throws ObjectStreamException {
return instance;
}
}

public class Client2 {

public static void main(String[] args) throws Exception {
SingletonDemo6 s1 = SingletonDemo6.getInstance();
SingletonDemo6 s2 = SingletonDemo6.getInstance();

System.out.println(s1);
System.out.println(s2);

//通过反射的方式直接调用私有构造器
//		Class<SingletonDemo6> clazz = (Class<SingletonDemo6>) Class.forName("com.bjsxt.singleton.SingletonDemo6");
//		Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null);
//		c.setAccessible(true);
//		SingletonDemo6  s3 = c.newInstance();
//		SingletonDemo6  s4 = c.newInstance();
//		System.out.println(s3);
//		System.out.println(s4);

//通过反序列化的方式构造多个对象
FileOutputStream fos = new FileOutputStream("d:/a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s1);
oos.close();
fos.close();

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));
SingletonDemo6 s3 =  (SingletonDemo6) ois.readObject();
System.out.println(s3);
}
}</span>


案例:测试多线程环境下五种创建单例模式的效率

<span style="font-size:14px;">public class Client3 {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
int threadNum = 10;
final CountDownLatch  countDownLatch = new CountDownLatch(threadNum);
for(int i=0;i<threadNum;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<1000000;i++){
//						Object o = SingletonDemo4.getInstance();
Object o = SingletonDemo5.INSTANCE;
}

countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();	//main线程阻塞,直到计数器变为0,才会继续往下执行!
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end-start));
}
}</span>


工厂模式:

实现了创建者和调用者的分离

详细分类: 简单工厂模式 工厂方法模式 抽象工厂模式

面向对象设计的基本原则:

OCP: 一个软件的实体应该对扩展开放, 对修改关闭

DIP:(依赖倒转原则 Dependence Inversion Principle ) 要针对接口编程,不要针对实现编程

LOD :只与你直接的朋友通信 而避免和陌生人通信

案例 简单工厂

<span style="font-size:14px;">简单工厂模式也叫静态工厂模式 就是工厂类一般是使用静态方法 通过接受的参数不同来放回不同的对象实例
对于增加新产品无能无力 不能修改代码的话  是无法扩展的
Client02 中不必需要知道  Audi ,Byd 类的细节
Audi ,byd  实现了 car 接口
public class Client02 {   //调用者
public static void main(String[] args) {
Car c1 =CarFactory.createCar("奥迪");
Car c2 = CarFactory.createCar("比亚迪");
c1.run();
c2.run();
}
}
public class CarFactory {
public static  Car createCar(String type){
if("奥迪".equals(type)){
return new Audi();
}else if("比亚迪".equals(type)){
return new Byd();
}else{
return null;
}
}
} </span>


案例 工厂方法模式

<span style="font-size:14px;">Audi ,byd  实现了 car 接口  一般我们还是使用简单工厂模式
public class Client {
public static void main(String[] args) {
Car c1 = new AudiFactory().createCar();
Car c2 = new BydFactory().createCar();
c1.run();
c2.run();
}
}
public interface CarFactory {
Car createCar();
}
public class AudiFactory implements CarFactory {
@Override
public Car createCar() {
return new Audi();
}
}
public class BydFactory implements CarFactory {

@Override
public Car createCar() {
return new Byd();
}
}</span>


案例 抽象工厂模式

<span style="font-size:14px;">增加产品族,而不是增加个别产品
public class Client {
public static void main(String[] args) {
CarFactory  factory = new LuxuryCarFactory();
Engine e = factory.createEngine();
e.run();
e.start();
}
}

public interface CarFactory {
Engine createEngine();
Seat createSeat();
}

public class LowCarFactory implements CarFactory {
@Override
public Engine createEngine() {
return new LowEngine();
}
@Override
public Seat createSeat() {
return new LowSeat();
}
}

public class LuxuryCarFactory implements CarFactory {

@Override
public Engine createEngine() {
return new LuxuryEngine();
}

@Override
public Seat createSeat() {
return new LuxurySeat();
}
}

public interface Engine {
void run();
}
class LuxuryEngine implements Engine{

@Override
public void run() {
System.out.println("转的快!");
}
}

class LowEngine implements Engine{

@Override
public void run() {
System.out.println("转的慢!");
}
}
public interface Seat {
void massage();
}

class LuxurySeat implements Seat {

@Override
public void massage() {
System.out.println("可以自动按摩!");
}

}
class LowSeat implements Seat {
@Override
public void massage() {
System.out.println("不能按摩!");
}

}</span>


案例 建造者模式

分离了对象子组件单独构造(由Builder来负责) 和装配(由Director负责) 从而可以构造出复杂的对象,这个模式适用于:某个对象的构建过程复杂的情况下使用

由于实现了构建和装配的解耦 不同的构建器 相同的装配 也可以做出不同的对象;实现了构建算法 装配算法的解耦,实现了更好的复用

开放中应用场景:

StringBuilder 类的append方法

sql中的PreparedStatement

JDOM中 DomBuilder ,SAXBuilder

<span style="font-size:14px;">public class AirShip {

private OrbitalModule orbitalModule;  //轨道舱
private Engine engine; //发动机
private EscapeTower escapeTower;  //逃逸塔
public void launch(){
System.out.println("发射!");
}
public OrbitalModule getOrbitalModule() {
return orbitalModule;
}
public void setOrbitalModule(OrbitalModule orbitalModule) {
this.orbitalModule = orbitalModule;
}
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 OrbitalModule{
private String name;
public OrbitalModule(String name) {
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) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

class EscapeTower{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public EscapeTower(String name) {
super();
this.name = name;
}
}
public interface AirShipBuilder {
Engine builderEngine();
OrbitalModule builderOrbitalModule();
EscapeTower  builderEscapeTower();
}
public class SxtAirShipBuilder implements AirShipBuilder {
//StringBuilder, 以后学习XML解析中,JDOM库中的类:DomBuilder,SaxBuilder
@Override
public Engine builderEngine() {
System.out.println("构建尚学堂牌发动机!");
return new Engine("尚学堂牌发动机!");
}

@Override
public EscapeTower builderEscapeTower() {

System.out.println("构建逃逸塔");
return new EscapeTower("尚学堂牌逃逸塔");
}

@Override
public OrbitalModule builderOrbitalModule() {
System.out.println("构建轨道舱");
return new OrbitalModule("尚学堂牌轨道舱");
}

}

public interface AirShipDirector {

/**
* 组装飞船对象
* @return
*/
AirShip   directAirShip();

}

public class SxtAirshipDirector implements AirShipDirector {

private AirShipBuilder builder;

public SxtAirshipDirector(AirShipBuilder builder) {
this.builder = builder;
}

@Override
public AirShip directAirShip() {
Engine e = builder.builderEngine();
OrbitalModule o = builder.builderOrbitalModule();
EscapeTower et = builder.builderEscapeTower();

//装配成飞船对象
AirShip ship = new AirShip();
ship.setEngine(e);
ship.setEscapeTower(et);
ship.setOrbitalModule(o);

return ship;
}

}
public class Client {
public static void main(String[] args) {

AirShipDirector director = new SxtAirshipDirector(new SxtAirShipBuilder());
AirShip ship = director.directAirShip();
System.out.println(ship.getEngine().getName());
ship.launch();
}
}</span>


原型模式

通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式

就是JAVA中的克隆技术,一某个对象为原型,复制出新的对象,新的对象具备原型对象的特点

优势有:效率高(直接克隆,避免了重新执行构造过程步骤)

克隆类似于new ,但是不同于new .new创建新的饿对象属性采用的是默认值,克隆出的对象的属性值完全和原型对象相同,并且克隆出的新对象改变不会影响原型对象。然后,在修改克隆对象的值

注意 浅克隆 和深克隆

案例 克隆的深浅克隆

<span style="font-size:14px;">public class Sheep2 implements Cloneable {   //1997,英国的克隆羊,多利!
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();  //直接调用object对象的clone()方法!

//添加如下代码实现深复制(deep Clone)
Sheep2 s = (Sheep2) obj;
s.birthday = (Date) this.birthday.clone();  //把属性也进行克隆!
//添加如上代码实现深复制(deep Clone)
return obj;
}

public Sheep2(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}

public Sheep2() {
}
}  </span>


案例 使用序列化和反序列化实现深复制

<span style="font-size:14px;">public class Client3 {
public static void main(String[] args) throws CloneNotSupportedException, Exception {
Date date = new Date(12312321331L);
Sheep s1 = new Sheep("少利",date);
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());

//		使用序列化和反序列化实现深复制
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream    oos = new ObjectOutputStream(bos);
oos.writeObject(s1);
byte[] bytes = bos.toByteArray();

ByteArrayInputStream  bis = new ByteArrayInputStream(bytes);
ObjectInputStream	  ois = new ObjectInputStream(bis);

Sheep s2 = (Sheep) ois.readObject();   //克隆好的对象!
System.out.println("修改原型对象的属性值");
date.setTime(23432432423L);
System.out.println(s1.getBirthday());
s2.setSname("多利");
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());

}
}</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: