设计模式(一)(单例,工厂,代理,代理工厂)

设计模式

1.单例模式
单例模式:为了解决同一对象要创建很多次的问题。因为同一个对象只创建一次,为了节约内存空间。比如很多用户浏览同一商品,当点击同一商品的信息时,其实创建相同的对象.
我们可以通过地址是否相等来判断对象实例化(new)了几次。
本次单例模式学习到的有三种:

  • 懒汉式
  • 饿汉式
  • 枚举
    一般情况下使用的是饿汉式,但是枚举是实现单例模式的最佳方法。
    注意最好让构造器和实例对象为私有的。


    懒汉式:
    懒汉式没那么“饿”,只有在真正需要的时候再去创建实例。所以在类中先判断实例是否为空,为空再去创建。但是在多线程中会出问题,因为可能同时创建多个实例。
public class OneDemo {
    public static void main(String[] args) {
        //先不用单例模式
        One o1=new One();
        One o2=new One();
        //如果o1和o2地址不同,说明创建了两个对象
        System.out.println(o1==o2);   //false  说明没有单例模式钱创建2个对象

        //单例模式
        One o3=One.getdanli();
        One o4=One.getdanli();
        System.out.println(o3==o4);   //true
    }
}
//一般类
class One{
    //使用单例模式:
    /*
    //因为static只有一份,后面可判断o变量
    // 有没有来鉴定One对象有没有被创建
     */
    private One(){}
    private volatile static One o=null;         //重点
    public static One getdanli(){
        if (o==null){				 //重点
            o=new One();
        }
        return o;
        //改为线程安全的
        if(o==null){
			synchronized (One.class){
				if(o==null){
					o=new One();
				}
			}
		}


    }
}

上面是一个双重校验锁实现对象实例
此外需要注意 o 采⽤ volatile 关键字修饰也是很有必要。
o 采⽤ volatile 关键字修饰也是很有必要的, o = new One();
这段代码其实是分为三步执⾏:

  1. 为 o 分配内存空间
  2. 初始化 o
  3. 将 o 指向分配的内存地址
    但是由于 JVM 具有指令重排的特性,执⾏顺序有可能变成 1i>3i>2。指令重排在单线程环境下不会出
    现问题,但是在多线程环境下会导致⼀个线程获得还没有初始化的实例。例如,线程 T1 执⾏了 1 和
    3,此时 T2 调⽤ getdanli() 后发现 o 不为空,因此返回
    uniqueInstance,但此时 o 还未被初始化。
    使⽤ volatile 可以禁⽌ JVM 的指令重排,保证在多线程环境下也能正常运⾏。

饿汉式:
饿汉式太饿啦~在类加载的时候就已经把类的实例创建出来了!

//单例模式
public class OneDemo {
    public static void main(String[] args) {
        hungerone ho1=hungerone.getHo();
        hungerone ho2=hungerone.getHo();
        System.out.println(ho1==ho2);   //true
    }
}
class hungerone{
    private static hungerone ho=new hungerone(); //重点
    private hungerone(){}
    public static hungerone getHo(){
        return ho;
    }
}

枚举:
利用枚举的特性,让JVM来帮我们保证线程安全和单一实例的问题。自动支持序列化机制,绝对防止多次实例化。

public class OneDemo {
    public static void main(String[] args) {
        enumone.INSTANCE.wh();
    }
}
enum enumone{
    INSTANCE;
    public void wh(){ }
}

2.工厂模式:
工厂模式:按照传入的参数,实例化(new)出相应的对象。有一个工厂类或方法,专门负责按照参数,生成相应的对象。把整个创建对象的过程,封装好。达到的效果是我们创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

下面的代码,我们在getper方法中根据我们传入的不同值new不同的类,达到一个封装的效果,我们只需要传入数字,不需要知道具体的类名。

//工厂模式
public class FactDemo {
    public static void main(String[] args) {
        //没使用设计模式
        person p1=new Stu();
        person p2=new Tea();
        p1.eat();
        p2.eat();
        //调用设计模式
        FactDemo f=new FactDemo();
        person p3=f.getper(1);
        person p4=f.getper(0);
        p3.eat();
        p4.eat();
    }
    //定义一个方法,创建对象
    public person getper(int i){
        if (i==0){
            return new Stu();
        }else if (i==1){
            return new Tea();
        }else {
            return null;
        }
    }
}
//接口,因为要使用多态来开发   人
interface person{
    void eat();
}
//
class  Stu implements person{
    @Override
    public void eat() {
        System.out.println("学生在食堂吃饭");
    }
}
class Tea implements person{
    @Override
    public void eat() {
        System.out.println("老师在教师食堂吃饭");
    }
}

3.代理模式:
代理模式:我们使用一个类代表另一个类的功能。通过第三方(代理方),去创建所须要的对象。
例子是 :
婚介中心:
男方: 找女友. 标准 会唱歌,会敲代码
中介: 完成男方的要求,调用女方。–代理方
女方: 小芳 小丽 满足上面的条件.
本例子我们通过中介来代理女方类的功能。

缺点:
①:代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展
②:每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。
解决方法:动态代理

public class homework {
    public static void main(String[] args) throws ParseException {
       proxy p1=new agency("yzl");
       proxy p2=new agency("zzp");
       p1.proxyperson();
       p2.proxyperson();
    }
}
interface proxy{
    void proxyperson();
    void proxypersontel();
}
class yzl implements proxy{

    @Override
    public void proxyperson() {
        System.out.println("代理人:yzl");
    }

    @Override
    public void proxypersontel() {
        System.out.println("代理人电话:111111");
    }
}
class zzp implements proxy{

    @Override
    public void proxyperson() {
        System.out.println("代理人:zzp");
    }

    @Override
    public void proxypersontel() {
        System.out.println("代理人电话:222222");
    }
}
//代理类   重点
class agency implements proxy{
    proxy p;
    public agency(String i){
        if (i.equals("yzl")){
            p=new yzl();
        }else if (i.equals("zzp")){
            p=new zzp();
        }else {
            p=null;
        }
    }

    @Override
    public void proxyperson() {
        p.proxyperson();
    }

    @Override
    public void proxypersontel() {
        p.proxypersontel();
    }
}

我们通过agency这个代理类来实现了代理模式

4.代理工厂模式:
建立在代理模式之上,针对多个类型,由工厂模式封装创建过程。通过代理得到各种类型对象的创建。
用这个模式是因为代理模式有个缺点:
上面的类在里面实例化后通过构造器,分配赋给不同的实例对象,但是可能会面临属性不够用的问题,可能还会有其他的要求,这时候我们就需要采用代理工厂模式。
例如:
车:
发动机厂商
空调厂商
外形厂商

选一辆车,得到三个类型,并这个类型都有可能是父类,下面分别还有很多子类。
下面的具体汽车的品牌就是代理类,在里面实现了对不同对象的实例化。
代码如下:

public class ProFactoryDemo {
    public static void main(String[] args) {
        BZpri b=new BZpri();
        b.createAir(0);
        b.createEn(1);
        BWMpri b2=new BWMpri();
        b2.createAir(1);
        b2.createEn(0);
    }
}
//发动机的父类
class Engine{
    int id;
    int hi;
}
//发动机厂商的子类
class FT extends Engine{
    public FT(){
        System.out.println("我是丰田的发动机");
    }
}
class DZ extends Engine{
    public DZ(){
        System.out.println("我是大众的发动机");
    }
}
//空调父类
class Air{
    String type;
    int pi;
}
//空调子类
class MD extends Air{
    public MD(){
        System.out.println("美的制造的空调");
    }
}
class GL extends Air{
    public GL(){
        System.out.println("格力制造的空调");
    }
}
//抽象工厂
interface Abstract{
    Engine createEn(int i);
    Air createAir(int i);
}
//代理类
class BZpri implements Abstract{
    Engine e;
    Air a;
    @Override
    public Engine createEn(int i) {
        if (i==0){
            e=new DZ();
        }else{
            e=new FT();
        }
        return e;
    }

    @Override
    public Air createAir(int i) {
        if (i==0){
            a=new MD();
        }else{
            a=new GL();
        }
        return a;
    }
}
class BWMpri implements Abstract{
    Engine e;
    Air a;
    @Override
    public Engine createEn(int i) {
        if (i==0){
            e=new DZ();
        }else{
            e=new FT();
        }
        return e;
    }

    @Override
    public Air createAir(int i) {
        if (i==0){
            a=new MD();
        }else{
            a=new GL();
        }
        return a;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值