1 Overview
Builder Pattern (Builder Pattern) is mainly used to "build a complex object step by step", in which "step by step" is a stable algorithm, while the various parts of the complex object change frequently. Therefore, the builder pattern is mainly used to solve the changing requirements of the "object part". This allows for more fine-grained control over the object construction process.
2 Example
Take the production of mobile phones as an example. Each mobile phone is divided into Screen, CPU and Battery. Now there are two types of mobile phones to be produced, Apple and Samsung.
Apple:
package org.scott.builder.before.use; import java.util.ArrayList; import java.util.List; /** * @author Scott * @version 2013-11-20 * @description */ public class ApplePhone { List<String> parts = new ArrayList<String>(); public void createCPU() { parts.add("CUP: Qualcomm"); } public void createScreen() { parts.add("SCREEN: JDI"); } public void createBattery() { parts.add("BATTERY: DeSai"); } public void show(){ System.out.print("产品部件信息:"); for(String part : parts){ System.out.print(part + "\t"); } } }
Samsung:
package org.scott.builder.before.use; import java.util.ArrayList; import java.util.List; /** * @author Scott * @version 2013-11-20 * @description */ public class SamsungPhone { List<String> parts = new ArrayList<String>(); public void createCPU() { parts.add("CUP: MTK"); } public void createScreen() { parts.add("SCREEN: Samsung"); } public void createBattery() { parts.add("BATTERY: DeSai"); } public void show(){ System.out.print("产品部件信息:"); for(String part : parts){ System.out.print(part + "\t"); } } }
Test client:
package org.scott.builder.before.use; /** * @author Scott * @version 2013-11-20 * @description */ public class BuilerTest { private static ApplePhone iphone = new ApplePhone(); private static SamsungPhone samPhone = new SamsungPhone(); public static void main(String args[]){ iphone.createCPU(); iphone.createScreen(); iphone.createBattery(); iphone.show(); samPhone.createCPU(); samPhone.createScreen(); samPhone.createBattery(); samPhone.show(); } }
Did you find a problem? That is, every process of producing mobile phones is the same. To be precise, the names of the processes are the same, but the specific processing of each process is different. The process remains unchanged. There are just a few steps. The specific processing of each process changes. , from this, we can extract the unchanging, "unchanged to cope with all changes", and hand over the changing to specific products.
How to do it specifically? This time the Builder mode comes in handy.
First, let’s take a look at the Phone interface:
package org.scott.builder.after.use; import java.util.ArrayList; import java.util.List; /** * @author Scott * @version 2013-11-20 * @description */ public abstract class Phone { protected List<String> parts = new ArrayList<String>(); public void add(String part){ parts.add(part); } public void show(){ System.out.print("产品部件信息:"); for(String part : parts){ System.out.print(part + "\t"); } } }
Apple mobile phone category:
package org.scott.builder.after.use; /** * @author Scott * @version 2013-11-20 * @description */ public class ApplePhone extends Phone{ }
Samsung mobile phone category:
package org.scott.builder.after.use; /** * @author Scott * @version 2013-11-20 * @description */ public class SamsungPhone extends Phone{ }
Then define an interface Builder for the production step:
package org.scott.builder.after.use; /** * @author Scott * @version 2013-11-20 * @description */ public interface Builder { public void buildCPU(); public void buildScreen(); public void buildBattery(); public Phone getPhone(); }
Builder for iPhone:
package org.scott.builder.after.use; /** * @author Scott * @version 2013-11-20 * @description */ public class ApplePhoneBuilder implements Builder{ private Phone phone = new ApplePhone(); @Override public void buildCPU() { phone.add("CUP: Qualcomm"); } @Override public void buildScreen() { phone.add("SCREEN: JDI"); } @Override public void buildBattery() { phone.add("BATTERY: DeSai"); } @Override public Phone getPhone() { return phone; } }
Builder for Samsung mobile phones:
package org.scott.builder.after.use; /** * @author Scott * @version 2013-11-20 * @description */ public class SamsungPhoneBuilder implements Builder{ private Phone phone = new SamsungPhone(); @Override public void buildCPU() { phone.add("CUP: MTK"); } @Override public void buildScreen() { phone.add("SCREEN: Samsung"); } @Override public void buildBattery() { phone.add("BATTERY: DeSai"); } @Override public Phone getPhone() { return phone; } }
Director who guides the specific production of mobile phones:
package org.scott.builder.after.use; /** * @author Scott * @version 2013-11-20 * @description */ public class Director { private Builder builder; public Director(Builder builder){ this.builder = builder; } public void construct(){ builder.buildCPU(); builder.buildScreen(); builder.buildBattery(); } }
Finally write a test class:
package org.scott.builder.after.use; /** * @author Scott * @version 2013-11-20 * @description */ public class BuilderTest { private static Builder iPhoneBuilder = new ApplePhoneBuilder(); private static Builder samPhoneBuilder = new SamsungPhoneBuilder(); public static void main(String[] args) { Director director = new Director(iPhoneBuilder); director.construct(); Phone phone = iPhoneBuilder.getPhone(); System.out.println("iphone"); phone.show(); director = new Director(samPhoneBuilder); director.construct(); phone = samPhoneBuilder.getPhone(); System.out.println("\nsamSung"); phone.show(); } }
Running result:
iphone 产品部件信息:CUP: Qualcomm SCREEN: JDI BATTERY: DeSai samSung 产品部件信息:CUP: MTK SCREEN: Samsung BATTERY: DeSai
The two Phone entity classes here are empty. If this is the case, then they can be omitted. If the Phone interface can also be omitted, in the end only the Director, Builder, and specific Bulider implementation classes will be left. Moreover, the ApplePhone class and the SamsungPhone class are two related classes. They are different mobile phone brands. If you encounter two or more classes that are not much related, there is no need for the public interface Phone to exist. But at this time, So how to determine the return value of the getPhone() method specified in the Builder interface?
Regardless of whether the return value type is ApplePhone or SamsungPhone, problems will arise because the type of the returned result is not uniform. At this time, you can define Phone as an empty interface (an interface that does not contain any methods), and then let these specific product classes that have no relationship with each other implement this interface. Then the return value type of the getPhone() method specified in the Builder interface It is still a Phone type, which solves the problem. However, in this case, there is no need to use Builder mode.
For more articles related to learning the builder pattern of java design patterns, please pay attention to the PHP Chinese website!