package com.learn.factory;
import java.util.ArrayList;
import java.util.List;
/**
* 他现在new的是Car,
*
* 在这里我讲了两个,一个是静态方法,单例,有人的又衍生一个多例
* 我觉得有这个名和没这个名都无所谓,明白是什么意思就可以了
*
* 任意定制交通工具的类型和生产过程
* 这是什么意思呢,首先这是两问
* 第一是任意定制交通工具的类型,
* 第二是任意定制生产过程
* 任意定制交通工具的类型,现在作为我们的客户来讲,
* 它只能开一种交通工具,这种交通工具叫Car
* 我想让他拥有多种交通工具,扩展到将来可能会用的交通工具
* 如果你明白多态的概念,在这里用interface主要是要模拟Spring
*
* 我们让Car去实现这个接口,如果我想要其他的交通工具
* 比如我想开一辆飞机,
*
* @author Leon.Sun
*
*/
public class Car implements Moveable {
/**
* 我们new了一个Car出来,变量car是一个静态变量
*
*/
private static Car car = new Car();
/**
* 如果我在这里写一个List,里面装的全是Car
* 我们可以做一个静态的初始化,把里面所有的Car都给他装上
* 将来你要getInstance的时候,可以返回cars里面的任何一个,
* 这种的又有人给他取了一个名字,这个叫多例
* 如果你学过JDBC,应该明白一个概念叫连接池
* 连接池就是上来二话不说先把所有的Connection建立到一个池子里头
* 那个池子是什么概念,是多例的概念
*
*/
// private static List<Car> cars = new ArrayList<Car>();
/**
* 我把构造方法写成private
* 除了Car自己之外,没有任何人可以new Car这个对象了
* 你就new不了Car了,这样我就限制了司机,
* 我们就限制了客户,来直接new我们的Car,
* 但是如果你不能new了也不行,不能new了一辆车也出不来
* 你想让他开车去东北,你总的给他一辆才行,
* 怎么给呢?典型的一个方法,
*
* 静态工厂方法和咱们现在要讲的工厂,简单工厂他们之间是有那么一点点小冲突
* 所以我现在先把Car设置成Public
*/
// private Car() {
public Car() {
}
/**
* instance的意思是实例对象
* 拿到一个对象
*
* 你要getInstance()拿Car是吗,
* 因为你不能new了,所以你只能通过这个方法来拿Car了
* 拿了半天我就可以返回给你静态的Car,
* 你第一次调用的时候我返回的是他,第二次返回的还是他,
* 至始至终永远永远的你只能开一个Car了,
* 所以只给司机辆车,
* 用这种最简单的方式就可以实现,
*
*/
public static Car getInstance() {
return car;
}
public void run() {
System.out.println("冒着烟奔跑中car......");
}
}
package com.learn.factory;
/**
* @author Leon.Sun
*
*/
public class Test {
public static void main(String[] args) {
/**
* 现在假设一个司机开着车去东北
* 我要去一个地方我要让车跑起来
* 我们第一个概念是要让大家考虑如果这个司机开一辆车
* 除了工厂之外还讲一下单例
* 如果说我只给司机一辆车
* 无论司机怎么去new Class,他最终拿到的只有一辆车
* 或者是若干辆车中的一辆
* 那这里头就带来一个概念,加入我允许司机去new这个Car,
* 他想new多少辆就new多少辆
* 你根本就没法限制只有一辆车给他,他要愿意他在大连把车扔了
* 再new一个新的再走,你根本就限制不了他,
* 那么我现在提个问题,我要向限制司机不让他去new,
* 也就是说Car的产生过程,车的产生过程由我自己去,
* 我该怎么办?
* 这次我要使用一辆Car的时候,我就必须通过Car的静态方法来拿到一辆Car
* 有人说你这是换汤不换药,调了getInstance方法,get方法里面
* 自己new了一个Car,那我将来再调getInstance当然是一个新Car,
* 你仍然不能限制司机想开哪辆就开哪辆,不过当你有了这层封装之后,
* Car自己可以控制自己的诞生过程了,
* 我们工厂讲什么呢?
* 工厂是生产产品的,工厂是讲我们自主生产自己的产品
* 而不再依赖于new,比如举个例子,
* 你想使用我的东西,比如你想开我们家的抽屉,
* new我们家的一个钱包,抽屉里装的全是钱
* 你要直接new,想拿钱就拿钱,
* 那肯定不行,但是要通过我的方法,get一个抽屉,才能拿到你要的那个抽屉,
* 那我在那个get方法里头,在取得对象的方法里头,可以做各种各样的限制
* 比如我们可以判断你是否有驾照,有驾照的话我才给你一个Car,
* if 你是不是我儿子,是我儿子我才给你抽屉装满钱,
* 虽然我们只封了一个方法,但是已经有本质的区别了,
* 原来我是交给别人直接new,现在是通过我自己定义的方法返回给他
* 在这里我还不是想怎么写就怎么写
* 现在我们是return 了一个 new Car
* 如果我从始至终只允许他开一辆Car,
* 我怎么办呢?
*
*/
// Car c = Car.getInstance();
/**
* 到时司机想开第二辆,他没法new,
* 只能调用getInstance()这个方法
*/
// Car c2 = Car.getInstance();
/**
* 这样我们就产生了一个Plane工厂
*
* 有没有其它的办法我不想换那么多,想换工厂我就去换他的实现就好了,
*
* 你要想在这替换方便,就要调用多态
* 你要用多态就要有父类子类这样一个概念,
*
* 而这个factory目前不能统一,要统一就得给factory一个父类
* 用一个抽象的概念把它给统一起来,所以基于这种考虑
*
*/
// PlaneFactory factory = new PlaneFactory();
// VehicleFactory factory = new PlaneFactory();
/**
* 在我们的客户类里,产生的就是Broom
* 其他的代码就不用变
* 我们现在用了工厂,我们不止可以产生交通工具
* 而且可以控制产生交通工具的生产过程
* 这个交通工具本身和生产工具本身都是由你自己来控制的
* 我们需要改的就一个地方
* 如果是用配置文件的话,这个地方都不用改
* 只要改配置文件就可以了
* 关于配置文件的概念我们一回再谈
* 这种的我们称之为简单工厂
* 我记得在最早的23种设计模式里头,
* 用C++作为例子的书里头,这种模式就称为工厂方法
* 无所谓,他叫什么不重要
* 重要的是你知道他是什么意思
*
*/
VehicleFactory factory = new BroomFactory();
/**
* 按照多态我应该这么写
*/
// Moveable m = new Plane();
/**
* 由他来产生具体的Plane
* 由他来产生具体的Plane还不够好
* 如果我们想随意的替换这个工厂
* 你要任意定制他的交通工具类型,就是自己抽象一个Moveable接口
* 子类去抽象他自己的一个抽象工具,可以是我要任意定制他的生产过程
* 比如说我现在想让他生产一辆Car,这里的代码仍然不想变
* 那么这个时候该怎么办,任意生产一辆Car我知道
*
* 我把Car换掉之后,createPlane也得换掉,
* 要换成createCar(),这样的话写了这么多工厂之后
* 我就发现我不能替换成原来的代码了,
* 就是这代码替换起来不方便了,
* 要想替换的方便的话怎么办,只有一种办法,
*
*
*/
Moveable m = factory.create();
/**
* 可是这两辆车是不是同一辆车
* 从头到尾你爱调用多少次方法就调多少次方法
* 但是无论如何我只能给你一辆车
* 这里面其实蕴含着两个模式
* 第一个模式叫单例,因为从始至终只有一个实例
* 第二个模式是后来有人起的模式,他们把getInstance()这个方法称之为静态工厂方法
* 最早写设计模式四个人里边,对于静态工厂方法并没有单独提出来
* 这是后来模式流行起来之后有的人想在这个概念上做一些精细的延伸
* 所以就提出来了一个静态工厂方法
* 我顺带在这里提一句
* 以后你就记住了,任何的方法,只要在他里面,控制了产生对象的逻辑
* 你都可以称之为工厂相关的方法,
* 设计模式你学到最后还是那句话,并不要局限于跳跳框框
* 到时是心中有剑手中无剑就对了
* 到最后你就不局限于条条框框
* 这个具体问题应该怎么设计
* 我就这么设计,你用的设计叫什么名我忘了
* 所以不要太拘泥于他的名字
* 不要咬文嚼字没有意思
* 这是静态的一个工厂方法
* 为什么叫工厂,因为他是产生Car产品的
* 因为他是静态的,所以叫静态方法
* 由于产生的只有一个,所以叫单例
*
*
*/
// if(c==c2) {
// System.out.println("same car");
// }
/**
* 你new的是谁,那就会调用谁的run方法
* 将来我想再扩展其他的交通工具呢
* 比如我想像哈利波特一样起着扫帚往外飞
* 那你只要new一个新的叫做扫帚,从Moveable继承
* 也就是重写它的run方法
* Moveable m = new 扫帚();
* 让m去飞,也就是说我实现了第一问,
* 任意定制交通工具,其实也不是完全的任意
* 必须去实现Moveable接口,可是现在我们只是定制了交通工具了
* 定制完交通工具之后,这个很简单
* 我们在这里还是用的new
* 那你new的时候就不会牵涉到各种权限检查,有没有这方面的资质啊
* 我要想new就直接new了,因为构造方法是公开的,
* 如果我这个时候能够对生产过程也进行定制的话
* 那这个时候应该怎么办呢?这个时候的办法是这样的,
* 比如我想控制飞机的生产过程,有人说用静态的,
* 这次我们改一下不用静态的,我们把产生飞机的东西给单独出来
* 产生飞机的东西叫做PlaneFactory飞机工厂
*/
m.run();
}
}
package com.learn.factory;
public interface Moveable {
/**
* interface里的方法默认就是public
*/
void run();
}
package com.learn.factory;
public class Plane implements Moveable {
@Override
public void run() {
System.out.println("扇着翅膀前进中plane......");
}
}
package com.learn.factory;
/**
* 作为飞机工厂来说,
*
* Plane也做同样的处理
* @author Leon.Sun
*
*/
public class PlaneFactory extends VehicleFactory {
/**
* 产生飞机
*/
// public Plane createPlane() {
// /**
// * 最简单的方式是return new Plane()
// * 至于你用单例还是
// * 这里面的实现并不重要,我们可以用工厂让他产生Plane
// *
// */
// return new Plane();
// }
/**
* 由于它是Plane的Factory
* 所以他返回的是Plane
* 我们会想一下这个处理过程,
* @return
*/
public Moveable create() {
return new Plane();
}
}
package com.learn.factory;
/**
* Car工厂
* 这样我们就拥有了一个CarFactory,不过在我们的测试类里面
*
* 我们让CarFactory从VehicleFactory继承
* @author Leon.Sun
*
*/
public class CarFactory extends VehicleFactory {
/**
* 它的返回值产生的是辆Car
*/
// public Car createPlane() {
// return new Car();
// }
/**
* 它的返回值是Moveable
* 不过由于它是CarFactory,所以我要让他产生一个新的Car
* @return
*/
public Moveable create() {
return new Car();
}
}
package com.learn.factory;
/**
* 产生交通工具的工厂
* 既然他是产生交通工具的工厂,他当然要产生交通工具
*
* 会想我们的处理过程,
* 这是我们的接口Moveable,
* 他有两个子类或者实现了的类,一个叫Car,一个叫Plane
* 与此对应的是有产生这些类的工厂,产生交通工具的工厂
* 还有他的子工厂,用来产生Car的CarFactory,
* 专门产生Plane的PlaneFactory,
* Car从Moveable继承,Plane也是从Moveable继承
* CarFactory从VehicleFactory继承,
* PlaneFactory也是从VehicleFactory继承
* 当我们的客户类想用这两个类的时候,就看他具体new出来的是哪个具体的VehicleFactory
* 如果new出来的是CarFactory,那么产生就是Car,
* 你new出来的是PlaneFactory,产生的就是Plane,
* 这样的话如果我们想添加其他的扩展内容,
* 比如broom,如果我还想控制生产工具的生产过程,
* 与此同时我就产生一个新的BroomFactory,
* 由他来产生的任何对象就是Broom了,
* 这样你有没有发现我们的系统在某一个维度上就产生扩展了
* 我们不仅可以产生新的交通工具,
* 而且还可以产生工具的生产过程
*
*
* @author Leon.Sun
*
*/
public abstract class VehicleFactory {
/**
* 产生可以移动的东西
* 这个create产出交通工具的工厂,
* create本身并不能决定具体怎么去实现
* 怎么去实现智能交给他的子类去决定
* 如果你是产生飞机的工厂,你就产生飞机,
* 如果你是产生汽车的工厂你就产生汽车,
* 所以这个方法我只能定义成抽象的
* 既然方法是抽象的,那这个类也是抽象的
*/
abstract Moveable create();
}
package com.learn.factory;
/**
* 让他去实现Moveable接口
* 与此同时我们还可以产生交通工具的交通工厂
* @author Leon.Sun
*
*/
public class Broom implements Moveable {
@Override
public void run() {
System.out.println("一路沙尘暴飞奔而来..broom.............");
}
}
package com.learn.factory;
public class BroomFactory extends VehicleFactory {
@Override
public Moveable create() {
return new Broom();
}
}