Builder Mode
Definition is also called the generator pattern. It can abstract the construction process of complex objects (abstract categories), so that different implementation methods of this abstract process can construct objects with different manifestations (attributes).
When an algorithm for creating a complex object should be independent of the components of that object, and the construction process must allow the constructed object to have different representations. We might consider using the Builder mode.
accomplish
1. Builder specifies an abstract interface for each component that creates a Product object. Usually, it contains abstract methods that create and return products, or it can be a concrete method, putting the creation process into the ConcreteBuilder class.
2. ConcreteBuilder implements the Builder interface to construct and assemble various components of the product.
3. Director is responsible for calling the appropriate builder to form the product. The director class generally does not depend on the product class. The builder class directly interacts with the director class.
4. Product represents a complex object to be constructed. ConcreateBuilder creates an internal representation of the product and defines its assembly process.
/** "Product" */ class Pizza { private String dough = ""; private String sauce = ""; private String topping = ""; public void setDough (String dough) { this.dough = dough; } public void setSauce (String sauce) { this.sauce = sauce; } public void setTopping (String topping) { this.topping = topping; } } ''/** "Abstract Builder" */'' abstract class PizzaBuilder { protected Pizza pizza; public Pizza getPizza() { return pizza; } public void createNewPizzaProduct() { pizza = new Pizza(); } public abstract void buildDough(); public abstract void buildSauce(); public abstract void buildTopping(); } /** "ConcreteBuilder" */ class HawaiianPizzaBuilder extends PizzaBuilder { public void buildDough() { pizza.setDough("cross"); } public void buildSauce() { pizza.setSauce("mild"); } public void buildTopping() { pizza.setTopping("ham+pineapple"); } } /** "ConcreteBuilder" */ class SpicyPizzaBuilder extends PizzaBuilder { public void buildDough() { pizza.setDough("pan baked"); } public void buildSauce() { pizza.setSauce("hot"); } public void buildTopping() { pizza.setTopping("pepperoni+salami"); } } ''/** "Director" */'' class Waiter { private PizzaBuilder pizzaBuilder; public void setPizzaBuilder (PizzaBuilder pb) { pizzaBuilder = pb; } public Pizza getPizza() { return pizzaBuilder.getPizza(); } public void constructPizza() { pizzaBuilder.createNewPizzaProduct(); pizzaBuilder.buildDough(); pizzaBuilder.buildSauce(); pizzaBuilder.buildTopping(); } } /** A customer ordering a pizza. */ class BuilderExample { public static void main(String[] args) { Waiter waiter = new Waiter(); PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder(); PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder(); waiter.setPizzaBuilder ( hawaiian_pizzabuilder ); waiter.constructPizza(); Pizza pizza = waiter.getPizza(); } }The client creates the Director object and configures it with the Builder object it wants. Director obtains the customer's request to create the product and finally obtains the product.
advantage
1. The process of constructing objects can be carefully controlled to produce different product objects.
2. Easy to expand. When there is a new product, you can just add a new ConcreteBuilder to achieve it.
Related Pattern Abstract Factory Pattern is similar to generators because it can also create complex objects. The main difference is that the generator pattern focuses on constructing a complex object step by step. The abstract factory model focuses on multiple series of product objects (simple or complex).
The generator returns the product in the last step, and for the abstract factory, the product returns immediately.
Prototype mode
Defining a prototype pattern is a type of creation pattern, which is characterized by "copying" an existing instance to return a new instance, rather than creating a new instance. The copied example is what we call a "prototype", which is customizable.
Prototype mode is mostly used to create complex or time-consuming instances, because in this case, copying an existing instance makes the program run more efficiently; or creating equal values, just naming different similar data.
accomplish
1. Client - Create a new object and then get another object through clone.
2. Prototype - Define a clone's own abstract method.
3. ConcretePrototype - Implement clone method.
public interface Prototype { public abstract Object clone ( ); } public class ConcretePrototype implements Prototype { public Object clone() { return super.clone(); } } public class Client { public static void main( String arg[] ) { ConcretePrototype obj1= new ConcretePrototype (); ConcretePrototype obj2 = ConcretePrototype)obj1.clone(); } } Example
1. Many elements in the game are repeated, and we can use the prototype mode to copy the same elements.
2. When making data charts, the first time we need to read data from the database and save it into the object. When we need to make other charts of the same data, using prototype mode can avoid rereading the database.
Related questions and implementations
1. If the number of prototypes to be created is not fixed, you can create a prototype manager. Before copying the prototype object, the client first checks whether there are prototype objects that meet the conditions in the prototype manager. If there is, it will use it directly. If not, clone one. This is called the registration form of prototype mode.
2. There are two types of copying: deep copy and shallow copy. When copying, the copy object and the prototype object share all the internal variables of the object, and the two objects have the same memory space and life cycle. Modification of the prototype object also modifies its replica and vice versa.
In Java, as long as you implement the Cloneable interface, you can call the clone method of the Object class to achieve shallow copying:
public class ShallowClone implements Cloneable { int age; Person person; public void setAge(int age){ this.age = age; } public void setPerson(String name){ person = new Person(name); } public Object clone() throws CloneNotSupportedException{ // The default java implements shallow copy return super.clone(); } } public class Person { String name; public Person(String name){ this.name = name; } } public class Test { public static void main(String[] args) throws CloneNotSupportedException { ShallowClone oldShallowClone = new ShallowClone(); oldShallowClone.setAge(20); oldShallowClone.setPerson("eric"); System.out.println("oldname: " + oldShallowClone.person.name + " age: " + oldShallowClone.age); ShallowClone newShallowClone = (ShallowClone)oldShallowClone.clone(); System.out.println("newname: " + newShallowClone.person.name + " age: " + newShallowClone.age); oldShallowClone.age = 30; oldShallowClone.person.name = "frank"; System.out.println("newname: " + newShallowClone.person.name + " age: " + newShallowClone.age); } } Output:
oldname: eric age: 20newname: eric age: 20newname: frank age: 20
It can be seen that the copying of the object is a reference to the object. When the value of the object is changed, the copied object will also change, and the basic type of Java is the copied value.
Below we implement deep copy:
public class DeepClone { int age; Person person; public void setAge(int age){ this.age = age; } public void setPerson(String name){ person = new Person(name); } public DeepClone(DeepClone deepClone){ this.age = deepClone.age; this.person = new Person(deepClone.person.name); } public DeepClone() {} public Object clone() throws CloneNotSupportedException{ return new DeepClone(this); } } public class Test { public static void main(String[] args) throws CloneNotSupportedException { DeepClone oldDeepClone = new DeepClone(); oldDeepClone.setAge(20); oldDeepClone.setPerson("eric"); System.out.println("oldname: " + oldDeepClone.person.name + " age: " + oldDeepClone.age); DeepClone newDeepClone = (DeepClone)oldDeepClone.clone(); System.out.println("newname: " + newDeepClone.person.name + " age: " + newDeepClone.age); oldDeepClone.age = 30; oldDeepClone.person.name = "frank"; System.out.println("newname: " + newDeepClone.person.name + " age: " + newDeepClone.age); } } Output:
oldname: eric age: 20newname: eric age: 20newname: eric age: 20
In the above copy method, we recreated an object and recreated the reference to implement deep copy.
advantage
1. Copying is better than new.
2. Simplify or hide the details of creating objects and copy them directly.