1. 策略设计模式
- 参考这篇文章:http://blog.csdn.net/chenjie19891104/article/details/6396458 讲的很清楚,策略设计模式。并且举了一个例子,很具有代表性。
- 先简单了解一下:
和模板方法模式的区别:
文章里还有一个例子:
备注:我来分解,解释一下这个例子。
将共同的方法定义成了一个接口,在这个接口中并没有这个共同方法的实现。
在Strategy类中,定义了一个方法execute,它的参数是拥有共同方法的接口类。
用户Context在调用Strategy的execute方法时,在定义这个共同的方法。 这样就大大提高了灵活性。因为公共方法也是可以后定义的。而不是在创建类的时候就定义好了。
下面把这个例子敲成代码
package net.mindview.interfaces; //公共方法回调类 interface SameCallback{ void doTheSame(); } //定义了一个策略类 interface Strategy { void execute(SameCallback sc); } //定义策略实现类 class concreteStrategy1 implements Strategy { @Override public void execute(SameCallback sc) { sc.doTheSame(); } } class concreteStrategy2 implements Strategy { @Override public void execute(SameCallback sc) { sc.doTheSame(); } } class concreteStrategy3 implements Strategy { @Override public void execute(SameCallback sc) { sc.doTheSame(); } } public class Context { public static void main(String[] args) { Strategy strategy = new concreteStrategy1(); //这个公共方法类 SameCallback sc = new SameCallback() { @Override public void doTheSame() { System.out.println("do same things"); } }; //那个策略需要用到公共方法类,调用即可,如果不用, 那就不在方法中小勇 strategy.execute(sc); strategy = new concreteStrategy2(); strategy.execute(sc); } }
2. 解耦
- 看下面这两个例子:
案例一 package net.mindview.interfaces.classprocessor; import java.math.BigInteger; import java.util.Arrays; /** * 处理器 */ class Processor { public String name(){ return getClass().getName(); }; //处理 Object process(Object input) { return input; } } /** * 大写处理器 */ class UpCase extends Processor { @Override public Object process(Object input) { return ((String)input).toUpperCase(); } } /** * 小写处理器 */ class DownCase extends Processor { @Override public Object process(Object input) { return ((String)input).toLowerCase(); } } /** * 分割数组处理器 */ class Splitter extends Processor { @Override public Object process(Object input) { return Arrays.toString(((String)input).toString().split(" ")); } } public class Apply { public static void process(Processor p, Object s){ System.out.println("Using Processor "+ p.name()); System.out.println(p.process(s)); } public static String s = "Disagreement with beliefs is by definition incorrect"; /** * 向本例这样, 创建一个能够根据所传递的参数对象的不同而具有不同行为的方法, * 被称为策略设计模式 * @param args */ public static void main(String[] args) { BigInteger b = new BigInteger("111111111111111"); process(new UpCase(), s); process(new DownCase(), s); process(new Splitter(), s); } /** * 这个类使用到了一个设计模式: 叫做策略设计模式 * 所谓 的策略设计模式指的是: 能够根据传递参数的不同而具有不同的行为的方法, 被称为策略设计模式 * 这类方法包含了所有执行的算法中固定不变的部分(这里是基类Processor,Object),而策略就是实际调用该方法时传递的实际参数, * 这部分参数是变化的,因此被称之为是"策略"部分. * 在main中看到了三种不同类型的策略应用到了String类型s对象上。 */ }
在这段代码中,定义了一个处理器,这个处理器有两个方法name()和process(). 然后定义了三个类, UpCase, DownCase,Spltter继承自这个类. 当我们在Apply类中定义
process(Process process, Object o)方法, 方法传递的参数是父类Process. 这样不仅可以处理父类,还可以处理子类. 在main方法中就有体现. 这就是策略设计模式的思想。但是,他还有局限性。如果在main中想调用Apply.process()方法, 则必须传递Process类或者子类,不能传递其他类。 下面这个案例滤波器就说明了这一点:
案例二 package net.mindview.interfaces.filters; //波形 public class Waveform { //计数器,第几波 private static long counter; private final long id = counter ++; //当前第几波 @Override public String toString() { return "Waveform " + id; } } package net.mindview.interfaces.filters; //滤波器 public class Filter { public String name(){ return getClass().getSimpleName(); } //加工 public Waveform process(Waveform input){ return input; } } package net.mindview.interfaces.filters; /** * 低频电磁波 */ public class LowPass extends Filter{ //切波的波长 double cutoff; public LowPass(double cutoff){ this.cutoff = cutoff; } //加工 @Override public Waveform process(Waveform input) { return input; } } package net.mindview.interfaces.filters; /** * 高频电磁波 */ public class HighPass extends Filter { //切波 double cutoff; public HighPass(double cutoff){ this.cutoff = cutoff; } //加工 @Override public Waveform process(Waveform input) { return input; } } package net.mindview.interfaces.filters; /** * 段波电磁波 */ class BandPass extends Filter { //其实切波点, 最高且波点 double cutoff ,highCutoff; public BandPass(double cutoff, double highCutoff){ this.cutoff = cutoff; this.highCutoff = highCutoff; } //加工 @Override public Waveform process(Waveform input) { return input; } }
在上面这个类中,我们定义了一个Filter滤波器。这里面有何Process中同名的两个方法。这个时候,我想复用案例一的Apply类中的process()方法,可不可以呢?不可以。因为Filter不是Process的子类。虽然, process中的方法体调用完全适用于继承Filter类的子类。为什么不可以呢?Apply就是一个应用类。应用类要处理一些列的类。他可以堆字符串进行处理, 应该也可以对波进行处理呀。现在不可以,因为Process类是一个实体类,他和Apply类中的process方法紧密耦合。如果能够实现解耦,那么,就可以将Apply类更加泛化。这就是将Process作为接口来处理
案例三 package net.mindview.interfaces.classprocessor2; import java.math.BigInteger; import java.util.Arrays; /** * 处理器 */ interface Processor { public String name(); //处理 Object process(Object input); } /** * 处理器有一部分是所有处理器都是一样的.有一部分是不同的. * 所以定义一个抽象类, 将共有方法定义为实体方法, 将各自实现的部分定义为抽象的 */ abstract class StringProcess implements Processor { @Override public String name() { return getClass().getSimpleName(); } public abstract Object process(Object input); } /** * 大写处理器 */ class UpCase extends StringProcess { @Override public Object process(Object input) { return ((String)input).toUpperCase(); } } /** * 小写处理器 */ class DownCase extends StringProcess { @Override public Object process(Object input) { return ((String)input).toLowerCase(); } } /** * 分割数组处理器 */ class Splitter extends StringProcess { @Override public Object process(Object input) { return Arrays.toString(((String)input).toString().split(" ")); } } public class Apply { public static void process(Processor p, Object s){ System.out.println("Using Processor "+ p.name()); System.out.println(p.process(s)); } public static String s = "Disagreement with beliefs is by definition incorrect"; /** * 向本例这样, 创建一个能够根据所传递的参数对象的不同而具有不同行为的方法, * 被称为策略设计模式 * @param args */ public static void main(String[] args) { BigInteger b = new BigInteger("111111111111111"); process(new UpCase(), s); process(new DownCase(), s); process(new Splitter(), s); } /** * 这个类使用到了一个设计模式: 叫做策略设计模式 * 所谓 的策略设计模式指的是: 能够根据传递参数的不同而具有不同的行为的方法, 被称为策略设计模式 * 这类方法包含了所有执行的算法中固定不变的部分(这里是基类Processor,Object),而策略就是实际调用该方法时传递的实际参数, * 这部分参数是变化的,因此被称之为是"策略"部分. * 在main中看到了三种不同类型的策略应用到了String类型s对象上。 */ }
- 在这个类里面,将Process定义为了接口。并且添加了StringProcess 字符串处理器类,提供了字符串处理的公用方法。这时如何修改案例二,才能让Apply成为一个公用类呢?其中一个方法是让Filter实现Process接口。但为题又来了,Filter中的process的输入输出参数都是Waveform类型的对象。而Process中process的输入输出都是Object。这时我们使用一个适配器来解决这个问题
package net.mindview.interfaces.filters2; import net.mindview.interfaces.classprocessor2.Processor; /** * 由于Filter中的process的输入输出参数都是Waveform,而Processor中process的输入 * 输出参数都是Object. 因此,写一个适配器,让Filter可以适配Processor类型的接口 * */ public class FilterAdapter implements Processor{ Filter filter; public FilterAdapter(Filter filter){ this.filter = filter; } @Override public String name() { return filter.name(); } @Override public Object process(Object input) { return filter.process((Waveform)input); } }
接下来看看Apply类如何处理的?
public class Apply { public static void process(Processor p, Object s){ System.out.println("Using Processor "+ p.name()); System.out.println(p.process(s)); } public static String s = "Disagreement with beliefs is by definition incorrect"; /** * 向本例这样, 创建一个能够根据所传递的参数对象的不同而具有不同行为的方法, * 被称为策略设计模式 * @param args */ public static void main(String[] args) { System.out.println("======处理字符串==========="); process(new UpCase(), s); process(new DownCase(), s); process(new Splitter(), s); System.out.println("======过滤波==========="); process(new FilterAdapter(new LowPass(1.0)), new Waveform()); process(new FilterAdapter(new HighPass(100.0)), new Waveform()); process(new FilterAdapter(new BandPass(1.0,10.0)), new Waveform()); } }
上面这个例子就示范了使用接口的好处,让类和方法解耦。同时还涉及到一个设计模式,
叫适配器设计模式。适配器设计模式有三种, 确切的说这是对象适配器模式.
3. 适配器设计模式
参考文章:http://blog.csdn.net/zxt0601/article/details/52848004
定义:适配器模式将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)。
属于结构型模式
主要分为三类:类适配器模式、对象的适配器模式、接口的适配器模式。
本文做以下约定
- 需要被适配的类,对象,接口被定义为源(目前已有的),简称为src(source).
- 最终需要输出的(我们需要的),简称dst(destination,也叫target)
- 适配器Adapter
一句话描述适配器模式:src->adapter->dist,即src以某种形式(类,对象,接口)给到适配器,适配器最终输出dist。
使用 场景
- 想要使用一个已经存在的类,但如果它的方法不满足需求时;
- 两个类的职责相同或相似,但是具有不同的接口时要使用它;
- 应该在双方都不太容易修改的时候再使用适配器模式适配,而不是一有不同时就使用它
第一类: 类适配器模式
一句话描述使用方法:Adapter类,通过继承src类,实现dist接口,完成src -> dist的适配.
以充电器为例:充电器本身就是一个适配器。输入的时220v电压, 输出的是5v电压。
首先, 有一个src类,本身是输出220v电压
package net.mindview.interfaces.adaptor; /** * 这是目前有的电压 200v * @author samsung * */ public class Voltage220 { public int output(){ int i = 220; System.out.println("这是220v电压"); return i; } }
然后, 有一个目标使用电压是5v
package net.mindview.interfaces.adaptor; /** * 我们需要使用的目标电压是5v * 这是一个5v电压的接口 * @author samsung * */ public interface Voltage5 { public int output(); }
定义一个适配器, 将220v电压经过处理后转换为5v电压供用户使用
package net.mindview.interfaces.adaptor; /** * 适配器,将220v电压输出为5v电压 * 适配器 继承src类, 实现dist类,实现从src->dist的转换 */ public class VoltageAdapter extends Voltage220 implements Voltage5{ @Override public int output() { int src = super.output(); System.out.println("适配器工作开始适配电压"); int dist = src/44; System.out.println("适配完成后输出电压:" + dist); return dist; } }
有一款手机需要充电,充电电压是5v
package net.mindview.interfaces.adaptor; public class Mobile { public void chargeing(Voltage5 v5){ if(v5.output() == 5){ System.out.println("正常充电"); } else { System.out.println("秒变note7"); } } }
使用手机的时候,需要将家里的220v电压转换为5v输出.调用适配器
public static void main(String[] args) { Mobile m = new Mobile(); m.chargeing(new VoltageAdapter()); }
输出:
===============类适配器============== 我是220V 适配器工作开始适配电压 适配完成后输出电压:5 电压刚刚好5V,开始充电
小结:
Java这种单继承的机制,所有需要继承的我个人都不太喜欢。
所以类适配器需要继承src类这一点算是一个缺点,
因为这要求dst必须是接口,有一定局限性;
且src类的方法在Adapter中都会暴露出来,也增加了使用的成本。
但同样由于其继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增强了。
第二类: 对象适配器模式
基本思路和类适配器一样, 只是将adapter类做了修改, 这次不继承src类,而是持有src类实例对象,以解决兼容性问题。
一句话总结使用方法:持有src类,实现dist类接口, 实现src -> dist的适配
(根据"合成复用规则", 在系统中尽量使用组合来代替继承)
package net.mindview.interfaces.adaptor; /** * 持有src类,实现dist类接口, 实现src -> dist的适配 * @author samsung * */ public class VoltageAdapter2 implements Voltage5{ Voltage220 voltage220; public VoltageAdapter2(Voltage220 voltage220){ this.voltage220 = voltage220; } @Override public int output() { System.out.println("得到220v电压"); int src = voltage220.output(); System.out.println("经过处理,输出5v电压"); int dist = src/44; System.out.println("最终使用的电压是"+dist+"v"); return dist; } }
测试结果:
得到220v电压 这是220v电压 经过处理,输出5v电压 最终使用的电压是5v 正常充电
小结:
对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。
根据合成复用原则,组合大于继承,
所以它解决了类适配器必须继承src的局限性问题,也不再强求dst必须是接口。
同样的它使用成本更低,更灵活。
第三类 接口适配器模式
也有文献称之为认适配器模式(Default Adapter Pattern)或缺省适配器模式。
定义:
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。
我们直接进入大家最喜爱的源码撑腰环节:
源码撑腰环节:
Android中的属性动画ValueAnimator
类可以通过addListener(AnimatorListener listener)
方法添加监听器,
那么常规写法如下:
ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100); valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); valueAnimator.start();
有时候我们不想实现Animator.AnimatorListener
接口的全部方法,我们只想监听onAnimationStart
,我们会如下写:
ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { //xxxx具体实现 } }); valueAnimator.start();
显然,这个AnimatorListenerAdapter
类,就是一个接口适配器。
查看该Adapter类源码:
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener, Animator.AnimatorPauseListener { @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationPause(Animator animation) { } @Override public void onAnimationResume(Animator animation) { } }
可见,它空实现了Animator.AnimatorListener
类(src)的所有方法.
对应的src类:
public static interface AnimatorListener { void onAnimationStart(Animator animation); void onAnimationEnd(Animator animation); void onAnimationCancel(Animator animation); void onAnimationRepeat(Animator animation); }
类图:
我们程序里的匿名内部类就是Listener1 2 这种具体实现类。
new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { //xxxx具体实现 } }
接口适配器模式很好理解,令我们的程序更加简洁明了。
总结
我个人理解,三种命名方式,是根据 src是以怎样的形式给到Adapter(在Adapter里的形式)来命名的。
类适配器,以类给到,在Adapter里,就是将src当做类,继承,
对象适配器,以对象给到,在Adapter里,将src作为一个对象,持有。
接口适配器,以接口给到,在Adapter里,将src作为一个接口,实现。
Adapter模式最大的作用还是将原本不兼容的接口融合在一起工作。
但是在实际开发中,实现起来不拘泥于本文介绍的三种经典形式,
例如Android中ListView、GridView的适配器Adapter,就不是以上三种经典形式之一,
我个人理解其属于对象适配器模式,一般日常使用中,我们都是在Adapter里持有datas,然后通过getView()/onCreateViewHolder()方法向ListView/RecyclerView提供View/ViewHolder。
Client是Lv Gv Rv ,它们是显示View的类。
所以dst(Target)是View。
一般来说我们有的src是数据datas,
即,我们希望:datas(src)->Adapter->View(dst)->Rv(Client)。
4. 适配接口
适配接口这一节,主要是再次强调了接口的好处. 可以使用策略设计模式, 在方法实际参数中调用接口, 用户使用的时候就可以根据实际情况传递实现了该接口的实现类. 灵活性更高. 同时, 课本中举了一个例子,Scanner的read方法中调用的就是readable接口。如果我想使用Scanner类(这时java类库中的类),有两种方式。
- 方式一:新类实现readable接口即可
- 方式二:如果类已定义好, 不方便修改, 可以使用适配器模式,让已写好的类适配Scanner类。
针对这两个方法,我们来看案例:
案例一(对应的方式一)
package net.mindview.interfaces; import java.io.IOException; import java.nio.CharBuffer; import java.util.Random; import java.util.Scanner; //随机单次 public class RandomWords implements Readable{ //首先生成一个全局的随机数. //特殊说明:创建一个Random对象的时候可以给定任意一个合法的种子数,种子数只是随机算法的起源数字,和生成的随机数的区 //间没有任何关系。其中47就是种子,那么为什么是作者要选择47作为种子呢? 原因如下: //由47做种后,产生的随机数更加体现了随机性。它没有什么具体的意义,只要理解随机数如果有一个种子, //那么会出现比较随机的随机数,而当种子是47的时候,随机率是最大的。 private static Random rand = new Random(46); //定义首字母,字母的范围已固定,不会改变,故定义为static final private static final char[] captials = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); //小写字母 private static final char[] lowers = "abcdefghijklmnopqrstuvwxyz".toCharArray(); //元音字母 private static final char[] vowels = "aeiou".toCharArray(); private int count; //计数,一共生成几个随机单词 public RandomWords(int count){ this.count = count; } @Override public int read(CharBuffer cb) throws IOException { if(count-- == 0) { return -1; } //生成一个大写字母 cb.append(captials[rand.nextInt(captials.length)]); //生成一个原因一个辅音 for(int i=0; i<4; i++){ cb.append(vowels[rand.nextInt(vowels.length)]); cb.append(lowers[rand.nextInt(lowers.length)]); } cb.append(" "); return 10;//返回字符数 } public static void main(String[] args) { Scanner s = new Scanner(new RandomWords(4)); while(s.hasNext()){ System.out.println(s.next()); } } }
案例二(对应方式二)
现在有一个写好的了,随机生成浮点数
package net.mindview.interfaces; import java.util.Random; //随机生成浮点数 public class RandomDoubles { private static Random rand = new Random(47); public double next(){ return rand.nextDouble(); } public static void main(String[] args) { RandomDoubles rd = new RandomDoubles(); for(int i=0; i<7 ;i++){ System.out.println(rd.next() + " "); } } }
下面我们使用适配器设计模式写一个类来进行适配。适配器模式有三种种, 这里是用的是类适配器模式, 还可以使用对象适配器模式
package net.mindview.interfaces; import java.io.IOException; import java.nio.CharBuffer; import java.util.Scanner; public class AdapterRandomDoubles extends RandomDoubles implements Readable{ private int count; public AdapterRandomDoubles(int count){ this.count = count; } @Override public int read(CharBuffer cb) throws IOException { if(count-- == 0){ return -1; } String result = Double.toString(next()) + " "; cb.append(result); return result.length(); } public static void main(String[] args) { Scanner s = new Scanner(new AdapterRandomDoubles(7)); while(s.hasNextDouble()){ System.out.println(s.nextDouble()+" "); } } }
下面使用的是对象适配器模式, 和类适配器模式基本相似。
package net.mindview.interfaces; import java.io.IOException; import java.nio.CharBuffer; import java.util.Scanner; public class AdapterRandomDoubles implements Readable{ private RandomDoubles rd; private int count; public AdapterRandomDoubles(RandomDoubles rd, int count){ this.rd = rd; this.count = count; } @Override public int read(CharBuffer cb) throws IOException { if(count-- == 0){ return -1; } String result = Double.toString(rd.next()) + " "; cb.append(result); return result.length(); } public static void main(String[] args) { Scanner s = new Scanner(new AdapterRandomDoubles(new RandomDoubles(), 7)); while(s.hasNextDouble()){ System.out.println(s.nextDouble()+" "); } } }
总结: 使用适配器模式, 我们可以在任何现有类之上添加类的接口,所以这意味着让方法接收接口类型,是一种让任何类都可以对该方法进行适配的方式。这就是使用接口而不使用类的强大之处。
4.本章设计的最后一个设计模式: 工厂设计模式 参考文章:
https://wenku.baidu.com/view/8293cb68302b3169a45177232f60ddccda38e62c.html###
在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象。 在这些情况,新对象的建立就是一个 “过程”,不仅是一个操作,像一部大机器中的一个齿轮传动。
模式的问题:你如何能轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程呢?
解决方案:建立一个工厂来创建对象
实现:
一、引言
1)还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用。
2)简单工厂模式:后来出现工业革命。用户不用去创建宝马车。因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建。比如想要320i系列车。工厂就创建这个系列的车。即工厂可以创建产品。
3)工厂方法模式时代:为了满足客户,宝马车系列越来越多,如320i,523i,30li等系列一个工厂无法创建所有的宝马系列。于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象。你需要指定某个具体的工厂才能生产车出来。
4)抽象工厂模式时代:随着客户的要求越来越高,宝马车必须配置空调。于是这个工厂开始生产宝马车和需要的空调。
最终是客户只要对宝马的销售员说:我要523i空调车,销售员就直接给他523i空调车了。而不用自己去创建523i空调车宝马车.
这就是工厂模式。
二、分类
工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
工厂模式可以分为三类:
1)简单工厂模式(Simple Factory)
2)工厂方法模式(Factory Method)
3)抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。
GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。
将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
三、区别
工厂方法模式:
- 一个抽象产品类,可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
- 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类可以创建多个具体产品类的实例。
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
两者皆可。
四、简单工厂模式
建立一个工厂(一个函数或一个类方法)来制造新的对象。分布说明引子:从无到有。客户自己创建宝马车,然后拿来用。