设计模式之————创建型设计模式

44 篇文章 0 订阅

创建型设计模式

//工厂模式
//1.简单工厂模式
public class FoodFactory {
 
    public static Food makeFood(String name) {
        if (name.equals("noodle")) {
            Food noodle = new LanZhouNoodle();
            noodle.addSpicy("more");
            return noodle;
        } else if (name.equals("chicken")) {
            Food chicken = new HuangMenChicken();
            chicken.addCondiment("potato");
            return chicken;
        } else {
            return null;
        }
    }
}
//总结:简单地说,简单工厂模式通常就是这样,一个工厂类 XxxFactory,里面有一个静态方法,
//根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。


//2.工厂模式
public interface FoodFactory {
    Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {
 
    @Override
    public Food makeFood(String name) {
        if (name.equals("A")) {
            return new ChineseFoodA();
        } else if (name.equals("B")) {
            return new ChineseFoodB();
        } else {
            return null;
        }
    }
}
public class AmericanFoodFactory implements FoodFactory {
 
    @Override
    public Food makeFood(String name) {
        if (name.equals("A")) {
            return new AmericanFoodA();
        } else if (name.equals("B")) {
            return new AmericanFoodB();
        } else {
            return null;
        }
    }
}
//客户端调用
public class APP {
    public static void main(String[] args) {
        // 先选择一个具体的工厂
        FoodFactory factory = new ChineseFoodFactory();
        // 由第一步的工厂产生具体的对象,不同的工厂造出不一样的对象
        Food food = factory.makeFood("A");
    }
}

//3.抽象工厂模式
// 得到 Intel 的 CPU
CPUFactory cpuFactory = new IntelCPUFactory();
CPU cpu = intelCPUFactory.makeCPU();
 
// 得到 AMD 的主板
MainBoardFactory mainBoardFactory = new AmdMainBoardFactory();
MainBoard mainBoard = mainBoardFactory.make();
 
// 组装 CPU 和主板
Computer computer = new Computer(cpu, mainBoard);


// 抽象为产品族
public static void main(String[] args) {
    // 第一步就要选定一个“大厂”
    ComputerFactory cf = new AmdFactory();
    // 从这个大厂造 CPU
    CPU cpu = cf.makeCPU();
    // 从这个大厂造主板
    MainBoard board = cf.makeMainBoard();
      // 从这个大厂造硬盘
      HardDisk hardDisk = cf.makeHardDisk();
 
    // 将同一个厂子出来的 CPU、主板、硬盘组装在一起
    Computer result = new Computer(cpu, board, hardDisk);
}



//单例模式 (https://blog.csdn.net/qq_27093465/article/details/50978916)

//1.饿汉式
public class Singleton {
    // 首先,将 new Singleton() 堵死
    private Singleton() {};
    // 创建私有静态实例,意味着这个类第一次使用的时候就会进行创建
    private static Singleton instance = new Singleton();
 
    public static Singleton getInstance() {
        return instance;
    }
    // 瞎写一个静态方法。这里想说的是,如果我们只是要调用 Singleton.getDate(...),
    // 本来是不想要生成 Singleton 实例的,不过没办法,已经生成了
    public static Date getDate(String mode) {return new Date();}
}
//优点:1.线程安全  2.在类加载的同时已经创建好一个静态对象,调用时反应速度快
//缺点:资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化


//2.懒汉式(饱汉式)
public class Singleton {
    // 首先,也是先堵死 new Singleton() 这条路
    private Singleton() {}
    // 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的
    private static volatile Singleton instance = null;
    /**
     * 加上volatile,禁止指令重排,造成的bug。
     * singletonInstance = new SingletonPattern3();
     * 看似一句话,但分三个步骤。
     * 1,memory = allocate(); //1:分配对象的内存空间
     * 2,ctorInstance(memory); //2:初始化对象
     * 3,instance = memory; //3:设置instance指向刚分配的内存地址
     * 但是经过重排序后如下:
     * 1,memory = allocate(); //1:分配对象的内存空间
     * 2,instance = memory; //3:设置instance指向刚分配的内存地址,此时对象还没被初始化,此时,instance已经不为null啦。
     * 3,ctorInstance(memory); //2:初始化对象
     * 在线程A初始化完成这段内存之前,线程B虽然进不去同步代码块,
     * 但是在同步代码块之前的判断就会发现instance不为空,但是在第一个IF判断就不为空了。
     * 此时线程B获得instance对象进行使用就可能发生错误。
     *
     * 

    /*
    在JVM中的及时编译存在指令重排序的优化,也就是说不能保证1,2,3执行的顺序,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是 1-3-2,则在 3 执行完毕、2 未执行之前,被线程二抢占了,
    这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。
    通过添加volatile就可以解决这种报错,因为volatile可以保证1、2、3的执行顺序,没执行玩1、2就肯定不会执行3,也就是没有执行完1、2instance一直为空

    */
 
    public static Singleton getInstance() {
        //这个地方可能有多个线程,在这排队,ABCD...
        if (instance == null) {
            // 加锁
            //若多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况
            //简单的操作给方法添加[synchronized],使之成为同步函数。但是就每个线程访问都得判断锁,效率就是问题。所以,才有后面的[双重锁形式]
            synchronized (Singleton.class) {
                // 这一次判断也是必须的,不然会有并发问题


                if (instance == null) {
                    //假设第一次A线程走到这,然后,呈挂起状态。这个时候,单例对象还未创建;
                    // 假设此时,B线程也来了判断单例对象==null成立,但是,因为A线程已经给里层的if判断上锁,所以,B只能在外等着。
                    //假设A线程被唤醒,那么,单例就会下面语句赋值,单例对象就创建啦。然后释放锁。B就可以进来啦。
                    //B线程进来之后,先判断单例对象是否为null,发现已经不是null啦,那么就不需要创建啦。
                    //CD线程同样,
                    //再往后面来的,第一个if就进不来啦,那就不会判断锁了。
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

//懒汉式的嵌套类(静态内部类)
public class Singleton3 {
 
    private Singleton3() {}
    //静态内部类只会被加载一次,线程安全
    // 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
    private static class Holder {
        private static Singleton3 instance = new Singleton3();
    }
    public static Singleton3 getInstance() {
        return Holder.instance;
    }
}

//枚举类的单例模式
public enum SingleTonDemo4 {
    INSTANCE; //虽然只有一行
}
public class TestEnum {
    
    //测试枚举单例
    public static void main(String[] args) {
        SingleTonDemo4 instance1 = SingleTonDemo4.INSTANCE;
        SingleTonDemo4 instance2 = SingleTonDemo4.INSTANCE;
        SingleTonDemo4 instance3 = SingleTonDemo4.INSTANCE;
        
        System.out.println(instance1 == instance3);
    }
    
}



//建造者模式


//1.简单例子(套路就是先 new 一个 Builder,然后可以链式地调用一堆方法,最后再调用一次 build() 方法,我们需要的对象就有了。)
Food food = new FoodBuilder().a().b().c().build();
Food food = Food.builder().a().b().c().build();

//2.完整例子(可以使用Lombok注解,@Builder简化书写)
class User {
    // 下面是“一堆”的属性
    private String name;
    private String password;
    private String nickName;
    private int age;
 
    // 构造方法私有化,不然客户端就会直接调用构造方法了
    private User(String name, String password, String nickName, int age) {
        this.name = name;
        this.password = password;
        this.nickName = nickName;
        this.age = age;
    }
    // 静态方法,用于生成一个 Builder,这个不一定要有,不过写这个方法是一个很好的习惯,
    // 有些代码要求别人写 new User.UserBuilder().a()...build() 看上去就没那么好
    public static UserBuilder builder() {
        return new UserBuilder();
    }
 
    public static class UserBuilder {
        // 下面是和 User 一模一样的一堆属性
        private String  name;
        private String password;
        private String nickName;
        private int age;
 
        private UserBuilder() {
        }
 
        // 链式调用设置各个属性值,返回 this,即 UserBuilder
        public UserBuilder name(String name) {
            this.name = name;
            return this;
        }
 
        public UserBuilder password(String password) {
            this.password = password;
            return this;
        }
 
        public UserBuilder nickName(String nickName) {
            this.nickName = nickName;
            return this;
        }
 
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
 
        // build() 方法负责将 UserBuilder 中设置好的属性“复制”到 User 中。
        // 当然,可以在 “复制” 之前做点检验
        public User build() {
            if (name == null || password == null) {
                throw new RuntimeException("用户名和密码必填");
            }
            if (age <= 0 || age >= 150) {
                throw new RuntimeException("年龄不合法");
            }
            // 还可以做赋予”默认值“的功能
              if (nickName == null) {
                nickName = name;
            }
            return new User(name, password, nickName, age);
        }
    }
}
//客户端的调用
public class APP {
    public static void main(String[] args) {
        User d = User.builder()
                .name("foo")
                .password("pAss12345")
                .age(25)
                .build();
    }
}



//原型模式
/*
Object 类中有一个 clone() 方法,它用于生成一个新的对象,当然,如果我们要调用这个方法,
java 要求我们的类必须先实现 Cloneable 接口,此接口没有定义任何方法,但是不这么做的话,
在 clone() 的时候,会抛出 CloneNotSupportedException 异常。
*/
/*
 java 的克隆是浅克隆,碰到对象引用的时候,克隆出来的对象和原对象中的引用将指向同一个对象。
 通常实现深克隆的方法是将对象进行序列化,然后再进行反序列化。
*/


//创建型模式总结
/*
创建型模式总体上比较简单,它们的作用就是为了产生实例对象,算是各种工作的第一步了,因为我们写的是面向对象的代码,所以我们第一步当然是需要创建一个对象了。

简单工厂模式最简单;工厂模式在简单工厂模式的基础上增加了选择工厂的维度,需要第一步选择合适的工厂;
抽象工厂模式有产品族的概念,如果各个产品是存在兼容性问题的,就要用抽象工厂模式。单例模式就不说了,为了保证全局使用的是同一对象,一方面是安全性考虑,一方面是为了节省资源;
建造者模式专门对付属性很多的那种类,为了让代码更优美;
原型模式用得最少,了解和 Object 类中的 clone() 方法相关的知识即可。

*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值