创建型模式总结

这里总结一下学习过程中遇到过的设计模式,并补充一些其它常见的设计模式
创建型模式结构型模式


参考: 地址1地址2


单例模式

单例模式:保证一个类仅有一个实例,并提供一个全局的访问点。

优点和使用场景

使用场景:日志对象、应用配置、线程池等。
优点

  1. 对于频繁使用的对象,可以节省创建对象所花费的时间。以及多个对象对系统内存的占用。
  2. 利用单例模式,可以实现在需要使用时才创建对象,而不像全局变量,一直占用资源。

单例模式的实现

两种实现方式:

  • 饿汉方式 -> 单例的实例在类装载时创建
  • 懒汉方式 -> 单例的实例在第一次被使用时创建
    注:单例类必须要有一个 private 访问级别的构造方法,static 的成员变量 和 方法。

饿汉模式

1.常用方式

		public class Single{
			private static Single uniqueInstance = new Single();
			private Single(){}
			public static Single getInstance(){
				return uniqueInstanc;
			}			
		}

JVM 加载 Single 类时,就自动创建实例
在静态初始化器中创建实例,保证了线程安全

2.枚举方式

		public enum Single {
		    INSTANCE;//定义一个枚举的元素,即Single实例
		    public Single getInstance(){
				return INSTANCE;
			}
			public void print(){
				System.out.print("序列化")}
		}

简洁、自动支持序列化机制,线程安全

懒汉模式

1.非线程安全版本

		public class Singleton {  
		    private static Singleton uniqueInstance;  
		    private Single(){}   

		    public static Single getInstance() {
				if (uniqueInstance == null) {  
					uniqueInstance = new Single();  
			     }  
			     return uniqueInstance;  
		      }  
		}

在第一次使用时(调用getInstance)才创建实例
当多个线程同时调用 getInstance 方法会出现问题

2.synchronized 版本,修改 getInstance 方法

		public static synchronized Single getInstance() {  
			if (instance == null) {  
	        	uniqueInstance = new Single();  
	    	}  
	      	return uniqueInstance;  
      }  

缺点: synchronized 锁会造成时间的消费,还可能发送阻塞

3.双重检查加锁版本

		public class Single {

		    //volatile保证,初始化后实例被修改后的可见性
		    private volatile static Single uniqueInstance;
		    private Single() {
		    }
		    public static Single getInstance() {
		        if (uniqueInstance == null) {
		            //第一次使用才会执行同步代码块
		            synchronized(Singleton.class) {
		                if (uniqueInstance == null) {
		                    uniqueInstance = new Single();
		                }
		            }
		        }
		        return uniqueInstance;
		    }
		}

相比直接使用 synchronized 大大节省了时间

4.静态内部类版本

		public class Singleton {  
		    private static class SingleHolder {  
		    	private static final Single INSTANCE = new Single();  
		    }  
		    private Single(){}  
		    public static final Single getInstance() {  
		    	return SingletonHolder.INSTANCE;  
		    }  
		}   

当调用 getInstance 才会装载 SingletonHolder 内部类


工厂模式

**工厂模式:**在基类中定义创建对象的一个接口,让子类决定实例化哪个类,工厂方法让一个类的实例化延迟到子类中进行。

工厂模式有三种分类

  1. 简单工厂模式
  2. 工厂方法模式
  3. 抽象工厂模式

工厂模式的作用

  1. 降低耦合度(将对象的创建和使用分开)
  2. 降低代码重复
  3. 降低维护成本(业务逻辑变化时,只需修改工厂)

简单工厂模式

简单工厂模式不符合 开发-封闭原则,所以不是23中常用的设计模式之一

角色分配

  1. 抽象产品角色:描述所有实例所共有内容的公共接口
  2. 具体产品角色:创建目标,实现接口的实现类
  3. 工厂角色:负责实现创建所有实例的内部逻辑

简单工厂模式实现
1.创建抽象产品角色,即接口

		public interface User{
			void name();
		}

2.创建具体产品角色,即实现类
(1)学生

		public class Stu implements User{
			public void name(){
				System.out.println("Students...");
			}
		}

(2)老师

		public class Teach implements User{
			public void name(){
				System.out.println("Teachers...");
			}
		}

3.创建工厂角色,即工厂类

		public class UserFactory{
			public static User getUser(String name){
				if(name==null)
					return null;
				if(name.qualsIgnoreCase("STUDENTS")){
					return new Stu();
				}else if(name.qualsIgnoreCase("TEACHERS")){
					return new Teach();
				}
			}
			return null;
		}

4.使用

		User stu = UserFactory.getUser("Students");
		stu.name();
		User tea = UserFactory.getUser("Teachers");
		tea.name();

由上面步骤可知,当我们增加 User 时,就需要修改工厂类中的 getUser) 方法,所以不符合开放-封闭原则

反射改善简单工厂
修改工厂类:

		public class UserFactory{
			public static Object getUser(Class<? extends User> clazz){
				Object obj = null;
				try{
					objc = class.forName(clazz.getName()).newInsatnce();
				}catch (Exception e){
					e.printStackTrace();
				}
				return obj;
		}

修改后虽然符合开放-关闭原则,但每次都需要传入具体产品类的全路径,比较麻烦(改善:反射+配置文件)

工厂方法模式

将简单工厂模式深化,使用最多的模式,不再使用统一的工厂类来创建所有对象,而是针对不同的对象提供不同的工厂,即每个对象对应一个工厂

角色分配

  1. 抽象产品角色
  2. 具体产品角色
  3. 抽象工厂角色
  4. 具体工厂角色

工厂方法模式实现
1.在简单工厂的基础上,增加一个工厂接口

		public interface Factory{
			public User getUser();
		}

2.创建具体工厂类
(1)学生工厂

		public class StuFactory implements Factory{
			public User getUser(){
				return new Stu();
			}
		}

(2)老师工厂

		public class TeaFactory implements Factory{
			public User getUser(){
				return new Teach();
			}
		}

3.使用

		Factort stufactory = new StuFactory();
		User stu = stufactory.getUser();
		stu.name();

抽象工厂模式

将工厂方法模式深化,工厂类不单可以创建一种产品,而是可以创建一组产品。

抽象工厂模式实现
不同专业学生对应不同老师
1.抽象产品
(1)学生

		public interface Stu{
			public void study();
		}

(2)老师

		public interface Tea{
			public void teach();
		}

2.具体产品
(1)数学专业学生

		public class Math_Stu implements Stu{
			public void study(){
				System.out.println("studing Math");
			}
		}

(2)计算机专业学生

		public class Computer_Stu implements Stu{
			public void study(){
				System.out.println("studing Comp uter");
			}
		}

(3)数学专业老师

		public class Math_Tea implements Tea{
			public void teach(){
				System.out.println("teaching Math");
			}
		}

(4)计算机专业老师

		public class Computer_Tea implements Tea{
			public void teach(){
				System.out.println("teaching Computer");
			}
		}

3.抽象工厂接口

		public interface Factory(){
			public Stu trainStu();
			public Tea trainTea();
		}

4.具体工厂类
(1)数学班

		public class Math_Factory implements Factory{
			public Stu trainStu(){
				return new Math_Stu();
			}
			public Tea trainTea(){
				return new Math_Tea();
			}
		}

(2)计算机班

		public class Computer_Factory implements Factory{
			public Stu trainStu(){
				return new Computer_Stu();
			}
			public Tea trainTea(){
				return new Computer_Tea();
			}
		}

5.使用

		Factory factory = new Math_Factory();
		Stu student = factory.trainStu();
		student.study();
		Tea teacher = factory,trainTea();
		teacher.teach();

建造者模式

建造者模式,是一种对象构建模式;一步步创建一个复杂的对象,允许用户通过指定复杂对象的类型和内容就可以构建,而不需要知道其内部的具体细节。

优缺点
优点:

  1. 将产品对象与创建过程解耦
  2. 不同的绝体建造者对应不同的产品对象
  3. 可以精细的控制产品的创建过程
  4. 增加新的具体建造者无需修改源代码

缺点:

  1. 不适合产品之间差异过大的情况
  2. 不适合产品内部很复杂的情况

和抽象工厂模式的区别
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。

角色分配

  1. 产品角色
  2. 抽象建造者
  3. 具体建造者
  4. 指挥者

建造者模式实现

1.产品类

		public class Product{
			private String partA;
			private String partB;
			private String partC;
			...//get/set方法
		}

2.抽象建造者

		public abstract class Builder{
			protected Product product = new Product();
			public abstract void buildPartA();
			public abstract void buildPartB();
			public abstract void buildPartC();

			public Product getResult(){
				return product;
			}
		}

3.具体建造者

		public class ConcreteBuilder extends Builder{
		    public void buildPartA(){
		    	...//get/set操作产品中的partA
		    }
		    public void buildPartB(){
		    	...
		    }
		    public void buildPartC(){
		    	...
		    }
		}

4.指挥者

		public class Director{
			private Builder builder;
			//构造方式注入
			public Director(Builder builder)
				this.builder = builder;
			}
			public Product construct(){
			//调用建造者的相关方法,返回一个完整的产品对象
		        builder.buildPartA();
		        builder.buildPartB();
		        builder.buildPartC();
		        return builder.getResult();
		    }
		}

5.使用

		Bulider c = new ConcreteBuilder();//创建具体建造者
		Director diretor = new Director(c);//创建相应产品的指挥者
		Product product = diretor.construct();//用过指挥者获得产品

原型模式

原型模式,使用原型实例指定将要创建的对象类型,通过复制这个实例创建新的对象。

使用场景

  1. 对象种类繁多,无法整合成一个类
  2. 难用根据类生成实例
  3. 解耦框架与生成的实例

优缺点
优点:

  1. 简化对象的创建过程,通过已有实例可以提高实例创建效率
  2. 可以动态减少和增加产品类
  3. 可以使用深克隆保存对象的状态

缺点:

  1. 每个类都需配备克隆方法,对已有类进行修改时会很麻烦
  2. 深克隆的代码较为复杂

角色分配

  1. 抽象原型
  2. 具体原型
  3. 使用者

原型模式实现

1.抽象原型

		//`java.lang.Cloneable 只是起到告诉程序可以调用clone方法的作用,它本身并没有定义任何方法
		public interface Product extends Cloneable{
		    public abstract void use(String s);
		    //creatClone方法是用于复制实例的方法
		    public abstract Product creatClone();
		
		}

2.具体原型

		public class ProductImp implements Product{
			ProductImp(String s){}
			public void user(String s){}
			//复制自己
			public Product creatClone(){
				Product p=null;
				try{
					p = (Product)clone();
				}catch(CloneNotSupportedException e){
					e.printStackTrace();
				}
				return p;
			}
		}

3.使用者

		public class Manager {
		    //保存实例的“名字”和“实例”之间的对应关系
		    private HashMap<String, Product> showcase=new HashMap<String, Product>();
		    //register方法将接收到的一组“名字”和“Product接口”注册到showcase中。这里Product是实现Product接口的实例,具体还未确定
		    public void register(String name ,Product product){
		        showcase.put(name, product);
		    }
		    public Product create(String productname){
		        Product p=showcase.get(productname);
		        return p.creatClone();
		    }
		}

4.使用

		Manager manager = new Manager();
		ProductImp demo = new ProductImp("x");//具体原型实例
		manager.register("show",demo);
		Product p = manager.create("show");//依据具体原型实例创建新的实例
		p.user("test");

猜你喜欢

转载自blog.csdn.net/MOKEXFDGH/article/details/88314418