This is the 16th day of my participation in Gwen Challenge

Creation pattern

Factory Method Pattern

Factory method pattern is divided into three types: ordinary factory pattern, multiple factory method pattern and static factory method pattern

Common Factory model
  • Create a factory class that creates instances of classes that implement the same interface:

- Interface for sending emails and SMS messagespublic interface Sender{
	public void Send(a); } - Implementation classpublic class MailSender implements Sender{
	@Override
	public void Send(a){
		System.out.println("MailSender Method");
	}
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
public class SmsSender implements Sender{
	@Override
	public void Send(a){
		System.out.println("SmsSender Method"); }} - Factory classpublic class SendFactory{
	public Sender produce(String type){
		if("mail".equals(type)){
			return new MailSender();
		}else if("sms".equals(type)){
			return new SmsSender();
		}else{
			System.out.println("Please input right type!"); }}} - Test classpublic class FactoryTest{
	public static void main(String[] args){
			SendFactory factory=new SendFactory();
			Sender sender=factory.produce("sms"); sender.Send(); }}Copy the code
Multiple factory method patterns
  • The multiple factory method pattern is an improvement over the normal factory method pattern
  • In the normal factory method pattern, an object cannot be created if an error string is passed
  • The Multiple Factory method pattern provides multiple factory methods to create objects separately

- SendFactory classpublic class SendFactory{
		public Sender produceMail(a){
				return new MailSender();
		}

		public Sender produceSms(a){
				return newSmsSender(); }} - Test classpublic class FactoryTest{
		public static void main(String[] args){
				SendFactory factory=newSendFactory(); Sender sender=factory.produceMail(); sender.Send(); }}Copy the code
Static factory method pattern
  • Set methods in multiple factory method patterns to static methods, calling them without creating an instance
- SendFactory
public class SendFactory{
		public static Sender produceMail(a){
				return new MailSender();
		}

		public static Sender produceSms(a){
				return new SmsSender();
		}
}




- FactoryTest
public class FActoryTest{
		public static void main(String[] args){ Sender sender=SenderFactory.produceMail(); sender.Send(); }}Copy the code
conclusion
  • The factory pattern is suitable for a large number of products that need to be created and have a common interface, and can be created using the factory method pattern:
    • Normal factory mode: If the incoming string is incorrect, the object cannot be created
    • The static factory method pattern, as opposed to the multiple factory method pattern, does not require an instance factory class
    • In most cases, the static factory approach pattern is used

Abstract Factory Pattern

  • Factory method pattern problem: Class creation depends on factory classes. If you want to extend the program, you must modify the factory class, which violates the closure principle
  • Abstract factory pattern: Create multiple factory classes. If you need to add new functionality, you can simply add the factory class without modifying the previous factory class

- Sender
public interface Sender{
		public void Sender(a); } - Two implementation classes - MailSenderpublic class MailSender implements Sender {
		@Override
		public void Send(a){
				System.out.println("This is MailSender!");
		}
}



  - SmsSender
public class SmsSender implements Sender{
		@Override
		public void Send(a){
				System.out.println("This is SmsSender!"); }} - Two factory classes - Factory class interface:public interface Provider{
		public Sender produce(a);
}
  - SendMailFactory
public class SendMailFactory implements Provider{
		@Override
		public Sender produce(a){
				return new MailSender();
		}
}
  - SendSmsFactory
public class SendSmsFactory implements Provider{
		@Override
		public Sender produce(a){
				return new SmsSender();
		}
}




- Test
public class Test{
		public static void main(String[] args){
				Provider provider=newSendMailFactory(); Sender sender=provider.produce(); sender.Send(); }}Copy the code
  • The advantage of the abstract factory model is that it is extensible:
    • If you need to add a function, such as sending instant messages
      • You just have to make an implementation class that implements the Sender interface
      • Make a factory class that implements the Provider interface

Singleton

  • Singleton pattern: Ensures that only one instance of a singleton exists within a JVM
  • Advantages of the singleton pattern:
    • Some classes are cumbersome to create, and for large objects, you can reduce a lot of overhead
    • The new operator is omitted, reducing the frequency of system memory usage and reducing the pressure of Garbage Collection (GC)
    • Some classes, such as the exchange’s core trading engine, control the trading process. If more than one class can be created, the system will be completely chaotic, so only the singleton pattern can ensure that the core trading server can control the whole process independently
- singleton classpublic class Singleton{
		/* Private static instance, prevent reference, assign to null, for lazy loading */
		private static Singleton instance=null;

		/* Private constructor to prevent instantiation */
		private Singleton(a){}/* Static factory method, create instance */
		public static Singleton getInstance(a){
				if(instance==null){
						instance=new Singleton();
				}

				return instance;
		}

		/* If the object is used for serialization, the object is guaranteed to remain the same before and after serialization */
		public Object ReadResolve(a){
				returninstance; }}Copy the code
  • Synchronized: getInstance = synchronized;
public static synchronized Singleton getInstance(a){
		if(instance==null){
			instance=new Singleton();
		}
		return instance;
}
Copy the code

Because synchronized locks the object, the use of synchronized, which locks the object every time getInstance() is called, degrades performance.

  • The lock is required only when the object is first created, and not after:
public static Singleton getInstance(a){
		if(instance==null) {synchronized(instance){
				if(instance==null){
					instance=newSingleton(); }}}return instance;
}
Copy the code

This seems to solve the problem by adding the synchronized keyword internally, which does not need to be locked on calls. Locking is required only when instance is null and an object is created. This improves performance, but it is still problematic

  • There are situations like this:
    • Object creation and assignment are done separately in Java
    • Instance =new Singleton() is executed in two steps
    • The JVM does not guarantee the order of these two operations:
      • It is possible that the JVM will allocate empty space for the new Singleton instance and then assign the value directly to the Instance member
      • Then initialize the Singleton instance
    • That can go wrong
  • Example:
    • A,B, two threads
      • Threads A and B simultaneously enter the first if judgment
      • Instance =new Singleton()
      • Due to optimization mechanisms within the JVM, the JVM first marks out some blank memory allocated to the Singleton and assigns it to the Instance member before initialization has begun, and THEN A leaves the synchronized block
      • B enters synchronized, and since instance is not null, it immediately leaves the synchronized block and returns the result to the program that called the method
      • At this point thread B intends to use the Singleton instance, and discovers that it has not been initialized, so it generates an error
  • The code needs further optimization:
private static class SingletonFactory{
	private static Singleton instance=new Singleton();
}

public static Singleton getInstance(a){
	return SingletonFactory.instance;
}
Copy the code
  • The reality is:
    • The singleton pattern uses inner classes to maintain the implementation of the singleton
    • JVM mechanisms ensure that when a class is loaded, the loading process is mutually exclusive
    • When getInstance is called for the first time, the JVM ensures that instance is created only once and that the memory assigned to instance is initialized
    • This method also uses the mutex mechanism only on the first call, which is a perfect solution to the low performance problem
public class Singleton{
	/* Private constructor to prevent instantiation */
	private Singleton(a){}

	/* Use inner classes to maintain singletons */
	private static class SingletonFactory{
		private static Singleton instance=new Singleton();
	}

	/* Get the instance */
	public static Singleton getInstance(a){
		return SingletonFactory.instance;
	}

	/* If the object is serialized, it is guaranteed that the object remains the same before and after serialization */
	public Object readResolve(a){
		returngetInstance(); }}Copy the code

This method, if you throw an exception in the constructor, the instance will never be created and will fail. Select the most suitable implementation method based on the actual scenario

  • Since synchronization is only required at class creation time, it is ok to simply separate creation from getInstance() and add synchronized to the creation separately:
public class SingletonTest{
	private static SingletonTest instance=null;

	private SingletonTest(a){}

	private static synchronized void syncInit(a){
		if(instance==null){
			instance=newSingletonTest(); }}public static SingletonTest getInstance(a){
		if(instance==null){
			syncInit();
		}
		returninstance; }}Copy the code
  • Use the “shadow instance” method to synchronize the properties of the singleton:
public class SingletonTest{
	private static SingletonTest instance=null;
	
	private Vector properties=null;
	
	public Vector getProperties(a){
		return properties;
	}

	private SingletonTest(a){}

	private static synchronized void syncInit(a){
		if(instance==null){
			instance=newSingletonTest(); }}public static SingletonTest getInstance(a){
		if(intance==null){
			syncInit();
		}
		return instance;
	}

	public void updateProperties(a){
		SingletonTest shadow=newSingletonTest(); properties=shadow.getProperties(); }}Copy the code
  • Singleton pattern features:
    • The singleton pattern is simple to understand, but difficult to implement
      • synchronous
      • asynchronous
    • The synchronized keyword locks objects, and should be used in appropriate places:
      • Note the objects and procedures that need to be locked, sometimes not the entire object and procedure
  • Using the static method of the class, you can achieve the effect of the singleton pattern
    • Class static methods and singleton pattern differences:
      • Static classes do not implement interfaces:
        • From a class perspective, yes, but that would break the static
        • Methods that are static are not allowed in an interface, and even when implemented are non-static
      • Singletons can be delayed:
        • Static classes are initialized when they are first loaded
        • Singleton lazy loading, because some classes are large, lazy loading helps improve performance
      • Singletons can be inherited:
        • Methods in singletons can be overridden
        • Static class internal methods are static and cannot be overridden
      • Singletons are more flexible:
        • In terms of implementation, a singleton is just an ordinary Java class that can implement other functions as long as it meets the basic requirements of the singleton
        • Static classes don’t work
    • The singleton pattern can be implemented internally with a static class

Builder Mode

  • The factory pattern provides a pattern for creating individual classes
  • Builder mode:The various products are centrally managed and used to create composite objects
    • Compound object: a class that has different properties
  • The Builder pattern is a combination of the abstract factory class pattern and the Test class
  • Code implementation: a Sender interface, two implementation classes MailSender and SmsSender
- Builder
public class Builder{
	private List<Sender> list=new ArrayList<Sender>();

	public void produceMailSender(int count){
		for(int i=0; i<count; i++){ list.add(newMailSender()); }}public void produceSmsSender(int count){
		for(int i=0; i<count; i++){ list.add(newSmsSender()); }}} - Test classpublic class Test{
	public static void main(String[] args){
		Builder builder=new Builder();
		builder.produceMailSender(10); }}Copy the code
  • The Builder pattern integrates many functions into a class that can create complex modules
  • Differences between builder mode and factory mode:
    • The factory pattern focuses on creating individual products
    • The Builder pattern focuses on creating conforming objects, multiple parts

Prototype mode

  • Prototype mode: Take an object as a prototype, copy it, clone it, and create a new object similar to the original object
  • The prototype pattern, while creative, is not related to the factory pattern
  • In Java, copying objects is done with clone()
- the prototype classpublic class Prototype implements Cloneable{
	public Object clone(a) throws CloneNotSupportedException{
		Prototype proto=(Prototype)super.clone();
		returnproto; }}Copy the code
  • A prototype class that simply implements the Cloneable interface, overriding the Clone () method
  • The Clone method can be rewritten to any name, since the Cloneable interface is an empty interface that can define any method name of the implementation class
  • The focus is onsuper.clone():
    • The super.clone() method calls the **clone() ** method of Object
    • In the Object class, the clone() method is native
  • Deep and shallow copies of objects:
    • Deep copy:
      • When an object is copied, both the base and reference types are recreated
      • Deep copy does a complete and thorough copy
    • A shallow copy:
      • When an object is copied, the variables of the base data type are recreated, and the reference type refers to the reference of the original object
public class Prototype implements Cloneable.Serializable{
	private static final long serialVersionUID=1L;
	private String string;
	private SerializableObject obj;

	/* Shallow copy */
	public Object clone(a) throws CloneNotSupportedException{
		Prototype proto=(Prototype)super.clone();
		return proto;
	}
	
	/* Deep copy */
	public Object clone(a) throws IOException,ClassNotFoundException{
	
	/* Write out the binary stream of the current object */
	ByteArrayOutputStream bos=new ByteArrayOutputStream();
	ObjectOutputStream oos=new ObjectOutputStream(bos);
	oos.writeObject(this);

	/* Read the new object generated by the binary stream */
	ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
	OnjectInputStream ois=new ObjectInputStream(bis);
	
	return ois.readObject();
	}
	
	public String getString(a){
		return string;
	}

	public void setString(String string){
		this.string=string;
	}

	public SerializableObject getObj(a){
		return obj;
	}

	public void setObj(SerializableObject obj){
		this.obj=obj; }}class SerializableObject implements Serializable{
		private static final long serialVersionUID=1L;
	}
Copy the code
  • To implement deep copy:
    • The binary input to read into the current object as a stream
    • Write out the object corresponding to the binary data