设计模式--创建型模式

设计模式

模式之间的关系如下:

原文出外

https://blog.csdn.net/weixin_42139375/article/details/82503232

创建型模式

方法解决的场景
工厂方法模式实现了同一接口的一些类进行实例的创建
抽象工厂模式 
单例模式 
建造者模式 
原型模式 

工厂方法模式分类

名称分类功能
工厂方法模式普通工厂

缺点:1、生成对象时,也容易错,

2、需要创建Factory

3、每次有一个新的类型引入时,需要重新修改SendFactory类,

多方法工厂

缺点:1、每次有一个新的类型引入时,需要重新修改SendFactory类,

2、需要创建Factory

静态方法工厂 

1、简单工厂模式

实现代码

//Sender.java
public interface Sender{
    void send();
}

//MailSender.java
public class MailSender implements Sender{
    @Override
    public void send(){
        System.out.println("this is MailSender function");
    }
}

//SmsSender.java
public class SmsSender implements Sender{
    @override
    public void send(){
        System.out.println("this is SmsSender function");
}

//SendFactory
public class SendFactory{
    public Sender produce(String senderName){
        if("mailsend".equalsIgnoreCase(senderName){
            return new MailSender();
        }else if("smssend".equalsIgnoreCase(senderName){
            return new SmsSender();
        }else{
            System.out.println("please input correct name");
            return null;
        }
    }
}

//MyMain.java
public class MyMain{
    public static void main(String[] args){
        SendFactory factory = new SendFactory();
        Sender sender = factory.produce("mailSend");
        sender.send();
    }
}

多方法工厂

代码如下:

//SendFactory.java
public class SendFactory{
    public Send produceMail(){
        return new MailSender();
    }
    public Send produceSms(){
        return new SmsSender();
    }
}

//MyMain.java
public class MyMain{
    public void main(String[] args){
        SendFactory factory = new SendFactory();
        Sender sender = factory.produceSms();
        sender.send()
    }
}

静态方法工厂

//SendFactory.java
public class SendFactory{
    public static Send produceMail(){
        return new MailSender();
    }
    public static Send produceSms(){
        return new SmsSender();
    }
}

//MyMain.java
public class MyMain{
    public void main(String[] args){
        Sender sender = SendFactory.produceSms();
        sender.send()
    }
}

2、工厂方法模式(Factory Method)

简单工厂模式有一个问题就是,类的创建依赖工厂类,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

如下方式,解决了静态方法工厂类,每次新添加一个类时,就需要修改工厂方法类的问题。

//Provider.java
public interface Provider{
    Sender produce();
}
//Sender.java
public interface Sender{
    public void send();
}
//MailSender.java
public class MailSender implements Sender{
    @Override
    public void send(){
        System.out.println("this is mailSender");
    }
}
//SmsSender.java
public class SmsSender implements Sender{
    @Override
    public void send(){
        System.out.println("this is SmsSender");
    }
}

//SmsSendFactory.java
public class SmsSendFactory implements Provider{
    @Override
    public Sender produce(){
        return SmsSender();
    }
}

//MailSendFactory.java
public class MailSendFactory implements Provider{
    @Override
    public Sender produce(){
        return MainSender();
    }
}

public class MyMain{
    public static void main(String[] args){
        Provider provider1 = new SmsFactory();
        Provider provider2 = new MailFactory();
        Sender sender1 = provider1.produce();
        Sender sender2 = provider2.produce();
        sender1.send();
        sender2.send();
    }
}

3、抽象工厂模式(abstract method)

方法 
工厂方法模式
一个抽象产品类,可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 
一个抽象工厂类,可以派生出多个具体工厂类。 
每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品。
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。   
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
工厂方法创建 "一种" 产品,他的着重点在于"怎么创建",也就是说如果你开发,你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随。 

抽象工厂需要创建一些列产品,着重点在于"创建哪些"产品上,也就是说,如果你开发,你的主要任务是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承。

//Provider.class
public interface Provider{
    Factory produce();
}
pulic interface KeyBoard{
    void myName();
}
public interface Mouse{
    void myName();
}
public class LGKeyBoard implements KeyBoard{
    @Override
    public void myName(){
        System.out.println("I'am LG KeyBoard");
    }
}
public class WRKeyBoard implements KeyBoard{
    @Override
    public void myName(){
        System.out.println("I'am WR KeyBoard");
    }
}

public class LGMouse implements Mouse{
    @Override
    public void myName(){
        System.out.println("I'am WR Mouse");
    }
}
public class WRMouse implements Mouse{
    @Override
    public void myName(){
        System.out.println("I'am WR Mouse");
    }
}

public class LGFactory implements Provider{
    private Mouse mouse;
    private KeyBoard keyBoard;
    public void produce(){
        this.mouse = new LGMouse();
        this.keyBoard = new LGKeyBoard();
    }
}
public class WRFactory implements Provider{
    private Mouse mouse;
    private KeyBoard keyBoard;
    public void produce(){
        this.mouse = new WRMouse();
        this.keyBoard = new WRKeyBoard();
    }
}
public class MyMain{
    public static void main(String[] args){
        Provider lg = new LGFactory();
        Provider wr = new WRFactory();
    }
}

4、单例模式(Singleton

在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在

实现单例的步骤:

一、私有化构造函数

二、在类中实例化类

三、通过public方法返回实例化对象

public class Singleton{
    private static Singleton instance = null;
    private Singleton(){

    }
    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
以上单例有如下问题:
1、在多线程时,无法保证只创建一个实例
2、实例只在调用时才被创建

public class Singleton{
    private static Singleton instance = new Singleton();
    private Singleton(){
    }
    public static Singleton getInstance(){
        return instance;
    }
}

采用了匿名内部类:
外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,
故而不占内存。即当SingleTon第一次被加载时,并不需要
去加载SingletonInner,只有当getInstance()方法第一次被调用时,才会去初始化INSTANCE,
第一次调用getInstance()方法会导致虚拟机加载SingletonInner类,这种方法不仅能确保线程
安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
原文链接:https://blog.csdn.net/mnb65482/article/details/80458571

public class Singleton{
    private Singleton(){
    }
    private static class SingletonInner{
        private static SingletonInner instance = new Singleton();
    }
    public SingletonInner getInstance(){
        return SingletonInner.instance;
    }
}

以下类出处https://www.cnblogs.com/leiqiannian/p/7922824.html
类中属性块方法加载顺序
一般顺序:静态块(静态变量)——>成员变量——>构造方法——>静态方法 
public class test {                         //1.第一步,准备加载类
    public static void main(String[] args) {
        new test();                         //4.第四步,new一个类,但在new之前要处理匿名代码块        
    }
    static int num = 4;                    //2.第二步,静态变量和静态代码块的加载顺序由编写先后决定 
    {
        num += 3;
        System.out.println("b");           //5.第五步,按照顺序加载匿名代码块,代码块中有打印
    }

    int a = 5;                             //6.第六步,按照顺序加载变量

    { // 成员变量第三个
        System.out.println("c");           //7.第七步,按照顺序打印c
    }

    test() { // 类的构造函数,第四个加载
        System.out.println("d");           //8.第八步,最后加载构造函数,完成对象的建立
    }

    static {                              // 3.第三步,静态块,然后执行静态代码块,因为有输出,故打印a
        System.out.println("a");
    }

    static void run()                    // 静态方法,调用的时候才加载// 注意看,e没有加载
    {
        System.out.println("e");
    }
}

类加载时:JAVA虚拟机在有且仅有的5种场景下会对类进行初始化。

行动场景
创建类的实例实例化对象,读取或设置一个静态字段时,调用一个类的静态方法
访问某个类或者接口的静态变量,或者对该静态变量赋值(如果访问静态编译时常量(即编译时可以确定值的常量)不会导致类的初始化如果类没进行初始化,需要先调用其初始化方法进行初始化
调用类的静态方法 
反射(Class.forName(xxx.xxx.xxx)) 
初始化一个类的子类(相当于对父类的主动使用),不过直接通过子类引用父类元素,不会引起子类的初始化 
Java虚拟机被标明为启动类的类(包含main方法的) 

 

4、建造者模式(Builder)

一个复杂对象的构建与他的表示分离,使用者可以一步一步的构建一个比较复杂的对象。

参数的对象时有三种方式:构造器重载,JavaBeans模式和builder模式

构造器重载方式
public class Product {
	private String id;
	private String name;
	private int age;

	public Product() {
	}

	public Product(String id) {
		this.id = id;
	}

	public Product(String id, String name) {
		this.id = id;
		this.name = name;
	}

	public Product(String id, String name, int age) {
		this.id = id;
		this.name = name;
		this.age = age;
	}
}

JavaBeans方式
public class Product {
	private String id;
	private String name;
	private int age;

	public Product() {
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

builder模式
public class ProductBuilder {
	private final String id;
	private final String name;
	private final int age;

	ProductBuilder(Builder builder){
		this.id = builder.id;
		this.name = builder.name;
		this.age = builder.age;
	}

	public static class Builder{
		private String id;
		private String name;
		private int age;
		Builder id(String id){
			this.id = id;
			return this;
		}
		Builder name(String name){
			this.name = name;
			return this;
		}
		Builder age(int age){
			this.age = age;
			return this;
		}

		public ProductBuilder build(){
			return new ProductBuilder(this);
		}
	}
}

ProductBuilder p3 = new ProductBuilder.Builder()
                            .id("10")
                            .name("phone")
                            .age(10)
                            .build();

 

5、原型模式(Prototype)

将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象

public class ProtoType implements Cloneable{
    public Object clone() throw CloneNotSupportException{
        ProtoType proto = (ProtoType)super.clone()
        return proto;
    }
}

浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。

实现深复制的三种情况

情况一:

如果自定的对象的属性引用了基本数据类型,只要自定的对象实现Cloneable接口,并且重写clone()方法;

情况二:

如果自定的对象的属性引用了非基本数据类型,自定的对象与相应引用非基本数据类型的属性都要实现Cloneable接口,并且重写clone()方法;

情况三:

采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象

情况一代码:
public class ProtoType implements Cloneable{
    public Object clone()throw CloneNotSupportException{
        ProtoType proto = (ProtoType)super.clone();
        return proto;
    }
}
情况二代码:
public class ProtoAType implements Cloneable{
    public Object clone()throw CloneNotSupportException{
        ProtoAType proto = (ProtoAType)super.clone();
        return proto;
    }
}
public class ProtoBType implements Cloneable{
    public Object clone()throw CloneNotSupportException{
        ProtoBType proto = (ProtoBType)super.clone();
        return proto;
    }
}
情况三代码:
public class ProtoCType{
    public ProtoCType deepCopy(){
        /* 写入当前对象的二进制流 */  
        ByteArrayOutputStream bos = new ByteArrayOutputStream();  
        ObjectOutputStream oos = new ObjectOutputStream(bos);  
        oos.writeObject(this);  
        /* 读出二进制流产生的新对象 */  
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  
        ObjectInputStream ois = new ObjectInputStream(bis);  
        return (ProtoCType)ois.readObject();  
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值