设计模式浅析(单例,抽象,代理)

常用的设计模式部分

双重检查锁实现单例模式

public Class Sington{

    private static volatile sington ;
    private Sington{

    }

    public Sington getInstance(){

        if(sington==null){
            synchronied(Sington.class){
                if(sington==null){
                    return new Sington();//3
                }

            }
        }

        return sington;
    }
}

// 缺点 还是可以通过反射创建多个实例
// 优点  并发安全
  1. 为什么getInstance方法不通过synchronized关键字实现
    实现同步的确可以通过在方法中添加synchronized关键字
    但是这很低效 每次调用这个方法都得承受内部锁开销 无论是否已经创建实例 并且同步只需要
    在第一次调用这个方法时才需要
  2. 为什么要使用volatile修饰
    不是两个if多重检验已经够了 为什么还要加个volatile关键字?
    这得从将getInstance方法翻译为汇编语言说起
    public Sington getInstance(){

        if(sington==null){
            
                     instance =new Sington();//3
              
        }

        return sington;
    }
;asm code generated for getInstance
054D20B0   mov         eax,[049388C8]      ;load instance ref
054D20B5   test        eax,eax             ;test for null
054D20B7   jne         054D20D7            ;转移语句 如果不相等则跳转
054D20B9   mov         eax,14C0988h        ;mov指令的意思是将14C0988h给eax
054D20BE   call        503EF8F0            ;allocate memory
054D20C3   mov         [049388C8],eax      ;store pointer in 
                                           ;instance ref. instance  
                                           ;non-null and ctor
                                           ;has not run
054D20C8   mov         ecx,dword ptr [eax] 
054D20CA   mov         dword ptr [ecx],1   ;inline ctor - inUse=true;
054D20D0   mov         dword ptr [ecx+4],5 ;inline ctor - val=5;
054D20D7   mov         ebx,dword ptr ds:[49388C8h]
054D20DD   jmp         054D20B0

054D20C3对应赋值 注意此时只是将一个没有进行初始化的对象赋给 [049388C8]
C8到D7是执行构造器的代码
如果此代码在执行 C3 行后且在完成该构造函数前被另一个线程中断,
另一个线程执行if语句后又被主线程抢去 主线程执行完毕返回 初始化完成的单例对象
此时线程2 将返回一个未初始化的对象
则双重检查锁定就会失败。

可以使用volatile修饰该变量 volatile保证了可见性 并禁止了重排序 保证同步 及使用volatile修饰的变量是按顺序执行的

单例模式使用static字段的实例实现

饿汉式

class Singleton
{
  private Vector v;
  private boolean inUse;
  private static Singleton instance = new Singleton();

  private Singleton()
  {
    v = new Vector();
    inUse = true;
    //...
  }

  public static Singleton getInstance()
  {
    return instance;
  }
}

代理模式

什么是代理模式 访问者不直接访问被访问者 而是通过代理
代理最终会将访问请求转发给真正的被访问者 他可以在转发访问之前和之后加入特定的逻辑

//在每天午夜0点到次日6点之间 request调用不被接受
public class ServiceControlSubjectProxy implements ISubject{
    private static final Logger=LogFactory.getLog(ServiceControlSubjectProxy.class);
    private Isubject subject;
    public ServiceControlSubjectProxy(ISubject s){
        this.subject=s;
    }
    public String request(){
        TimeOfDay startTime=new TimeOfDay(0,0,0);
        TimeOfDay endTime=new TimeOfDay(5,59,59);
        TimeOfDay currentTime=new TimeOfDay();
        if(currentTime.isAfter(startTime) && current.isBefore(endTime))
            return null;
            Sting originalRestult=subject.request();

            return "Proxy:"+originalResult;

    }
}

ISubject target=new SubjectImpl();
ISubject finalSubject=new ServiceControlSubjectProxy(target);
finalSubject.request();
//为什么SubjectImpl 和 ServiceControlSubjectProxy都实现了相同的接口 这是因为 
//ServiceControlSubjectProxy作为代理对象必须实现被代理对象的同一个接口才具有相同功能

上诉静态代理存在弊端
如果存在Joinpoint相同(request()方法和执行横切逻辑一样) 但是对应的目标对象类型是不一样的时候
就要为不同对象实现不同的代理对象 尽管其他都一样

工厂模式

简单工厂 现在有一个工厂生产手机 生产的手机有苹果,和小米
怎样设计这个类并实现他呢

  1. 需要一个手机接口
  2. 苹果,小米类分别实现这个接口
  3. 创建一个工厂类
  4. 该类的某个方法返回值是手机接口 将根据参数返回具体的实例
public interface Phone {
    void make();
}

public class MiPhone implements Phone {
    public MiPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make xiaomi phone!");
    }
}

public class IPhone implements Phone {
    public IPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make iphone!");
    }
}


public class PhoneFactory {
    public Phone makePhone(String phoneType) {
        if(phoneType.equalsIgnoreCase("MiPhone")){
            return new MiPhone();
        }
        else if(phoneType.equalsIgnoreCase("iPhone")) {
            return new IPhone();
        }
        return null;
    }
}

但是这种写法的弊端 是实现类和工厂耦合
`` 并且这上述方式不符合开闭原则(对于扩展是开放的 对于修改是关闭的)上诉代码 要再添加一个HUAWEI手机 就得修改if else语句
当然可以通过反射解决

public static Phone getPhone(Class c){
	Phone  phone=null;
	try{
		phone=(Phone)Class.forName(c.getName()).newInstance();
    }catch(Exception e)
    {
        e.printSackTrace();

   }
   return  phone;
}

换句话说 如果要优化简单工厂模式 那么就得 就得删掉if else
怎么删掉 根据时间换空间 空间换时间的思路 必然要构造多个类

通过定义一个抽象工厂接口 将具体的生产的类交给具体的抽象接口派生类

这些派生类去构造对象

工厂方法模式
  1. 定义一个抽象工厂接口 即产品的生产接口 它将生产任务交给不同的派生类工厂

  2. 定义具体的派生类工厂 实现抽象工厂接口

public interface AbstractFactory {
    Phone makePhone();
}
public class XiaoMiFactory implements AbstractFactory{
    @Override
    public Phone makePhone() {
        return new MiPhone();
    }
}
public class AppleFactory implements AbstractFactory {
    @Override
    public Phone makePhone() {
        return new IPhone();
    }
}
public class Demo {
    public static void main(String[] arg) {
        AbstractFactory miFactory = new XiaoMiFactory();
        AbstractFactory appleFactory = new AppleFactory();
        miFactory.makePhone();            // make xiaomi phone!
        appleFactory.makePhone();        // make iphone!
    }
}

这样就避免了简单工厂方法中的耦合
题外话:
但是为什么 这里不使用泛型??
使用泛型如果想生产另一类 直接改变<>中的内容就好了 可能这回导致另一个问题 泛型被擦除了怎么办

抽象工厂模式

上面两种模式不管工厂怎么细分 都只是针对一类产品 如果要生产另外的产品
只需在抽象工厂接口中添加新的方法 用于生成新的类

public interface AbstractFactory {
    Phone makePhone();
    PC makePC();
}

public class XiaoMiFactory implements AbstractFactory{
    @Override
    public Phone makePhone() {
        return new MiPhone();
    }
    @Override
    public PC makePC() {
        return new MiPC();
    }
}

public class AppleFactory implements AbstractFactory {
    @Override
    public Phone makePhone() {
        return new IPhone();
    }
    @Override
    public PC makePC() {
        return new MAC();
    }
}

参考

https://blog.csdn.net/chenchaofuck1/article/details/51702129 [Java单例模式中双重检查锁的问题]
https://www.cnblogs.com/yssjun/p/11102162.html [设计模式之工厂模式(factory pattern)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值