阅读Head First的笔记
除了使用new操作符之外,还有更多制造对象的方法。你将了解到实例化这个活动不应该总是公开地进行,也会认识到初始化经常造成“耦合”问题。
工厂模式将从复杂的依赖中帮你脱困。
简单工厂模式:
简单工厂模式的核心是定义一个创建对象的接口,将对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。
但是压力来自于增加更多的比萨类型
现在最好将创建对象移至orderPizza之外,把创建比萨的代码移到另一个对象中,由这个新对象专职创建比萨。
我们称这个新对象为:“工厂”
工厂处理创建对象的细节,一旦有了工厂,orderPizza()就变成了此对象的客户。当需要比萨时,就叫比萨工厂做一个。
其实简单工厂不是一个设计模式,反而比较像是一种编程习惯。
public class Pizza {
private String pizzaName;
public String getPizzaName() {
return pizzaName;
}
public void setPizzaName(String pizzaName) {
this.pizzaName = pizzaName;
}
}
/**
* 简单Pizza工厂
*/
public class PizzaFactory {
public static Pizza getPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")){
pizza = new CheesePizza();
}else if(type.equals("greek")){
pizza = new GreekPizza();
}
return pizza;
}
}
public class PizzaStore {
void prepare(String pizzaName){
System.out.println("准备中 "+pizzaName);
System.out.println("和面团中....");
System.out.println("添加酱汁");
System.out.println("添加配料:");
}
void bake(){
System.out.println("准备烘烤 25 分钟...");
}
void cut(){
System.out.println("烘烤完成,进行切割");
}
void box(){
System.out.println("切割完毕,进行装盒");
}
public Pizza orderPizza(String type){
Pizza pizza = PizzaFactory.getPizza(type);
assert pizza != null;
prepare(pizza.getPizzaName());
bake();
cut();
box();
return pizza;
}
}
public class GreekPizza extends Pizza{
public GreekPizza(){
this.setPizzaName("GreekPizza!!");
}
}
public class CheesePizza extends Pizza{
public CheesePizza(){
this.setPizzaName("CheesePizza!!");
}
}
/**
* 简单工厂模式:
* 将创建一类对象的细节封装在一个对象中,外界只需要通过这个对象(工厂对象)根据特定的参数直接获取想要的对象即可。
*/
public class MainTest {
public static void main(String[] args) {
Pizza pizza = new PizzaStore().orderPizza("cheese");
}
}
简单工厂模式的优缺点:
简单工厂模式提供专门的工厂类用于创建对象,实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需知道具体产品类所对应的参数即可,通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
但缺点在于不符合“开闭原则”,每次添加新产品就需要修改工厂类。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
为了解决简单工厂模式的问题,出现了工厂方法模式
工厂方法模式:
工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。在使用时,用于只需知道产品对应的具体工厂,关注具体的创建过程,甚至不需要知道具体产品类的类名,当我们选择哪个具体工厂时,就已经决定了实际创建的产品是哪个了。
但缺点在于,每增加一个产品都需要增加一个具体产品类和实现工厂类,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
- 抽象工厂 AbstractFactory: 工厂方法模式的核心,是具体工厂角色必须实现的接口或者必须继承的父类,在 Java 中它由抽象类或者接口来实现。
- 具体工厂 Factory:被应用程序调用以创建具体产品的对象,含有和具体业务逻辑有关的代码
抽象产品 AbstractProduct:是具体产品继承的父类或实现的接口,在 Java 中一般有抽象类或者接口来实现。 - 具体产品 Product:具体工厂角色所创建的对象就是此角色的实例。
public class CaliforniaPizzaFactory implements PizzaFactory{
@Override
public Pizza getPizza(String type) {
Pizza pizza = null;
if(type.equals("California1")){
pizza = new CaliforniaPizza1();
}
return pizza;
}
}
public class ChicagoPizzaFactory implements PizzaFactory {
@Override
public Pizza getPizza(String type) {
Pizza pizza = null;
if(type.equals("ChicagoPizza1")){
pizza = new ChicagoPizza1();
}
return pizza;
}
}
public class NYPizzaFactory implements PizzaFactory{
@Override
public Pizza getPizza(String type) {
Pizza pizza = null;
if(type.equals("NY1")){
pizza = new NYPizza1();
}else if(type.equals("NY2")){
pizza = new NYPizza2();
}
return pizza;
}
}
public interface PizzaFactory {
Pizza getPizza(String type);
}
public class CaliforniaPizza1 extends Pizza{
public CaliforniaPizza1(){
this.setPizzaName("CaliforniaPizza1");
}
}
public class ChicagoPizza1 extends Pizza{
public ChicagoPizza1(){
this.setPizzaName("ChicagoPizza1");
}
}
public class NYPizza1 extends Pizza{
public NYPizza1(){
this.setPizzaName("NYPizza1");
}
}
public class NYPizza2 extends Pizza{
public NYPizza2(){
this.setPizzaName("NYPizza2");
}
}
public class Pizza {
private String pizzaName;
public String getPizzaName() {
return pizzaName;
}
public void setPizzaName(String pizzaName) {
this.pizzaName = pizzaName;
}
}
public class PizzaStore {
private PizzaFactory pizzaFactory;
public PizzaStore(PizzaFactory pizzaFactory){
this.pizzaFactory = pizzaFactory;
}
void prepare(String pizzaName){
System.out.println("准备中 "+pizzaName);
System.out.println("和面团中....");
System.out.println("添加酱汁");
System.out.println("添加配料:");
}
void bake(){
System.out.println("准备烘烤 25 分钟...");
}
void cut(){
System.out.println("烘烤完成,进行切割");
}
void box(){
System.out.println("切割完毕,进行装盒");
}
public Pizza orderPizza(String type){
Pizza pizza = pizzaFactory.getPizza(type);
assert pizza != null;
prepare(pizza.getPizzaName());
bake();
cut();
box();
return pizza;
}
}
public class MainTest {
public static void main(String[] args) {
//纽约分店
PizzaStore pizzaStore1 = new PizzaStore(new NYPizzaFactory());
pizzaStore1.orderPizza("NY1");
//芝加哥分店
PizzaStore pizzaStore2 = new PizzaStore(new ChicagoPizzaFactory());
pizzaStore2.orderPizza("ChicagoPizza1");
//加州分店
PizzaStore pizzaStore3 = new PizzaStore(new CaliforniaPizzaFactory());
pizzaStore3.orderPizza("California1");
}
}
抽象工厂模式:
在工厂方法模式中,我们使用一个工厂创建一个产品,一个具体工厂对应一个具体产品,但有时候我们需要一个工厂能够提供多个产品对象,而不是单一的对象,这个时候我们就需要使用抽象工厂模式。
public class CaliforniaPizza1 extends Pizza {
public CaliforniaPizza1(){
this.setPizzaName("CaliforniaPizza1");
}
}
public class ChicagoPizza1 extends Pizza {
public ChicagoPizza1(){
this.setPizzaName("ChicagoPizza1");
}
@Override
public void bake(){
System.out.println("ChicagoPizza1 烘烤流程变啦");
}
}
public class NYPizza1 extends Pizza {
public NYPizza1(){
this.setPizzaName("NYPizza1");
}
}
public class NYPizza2 extends Pizza {
public NYPizza2(){
this.setPizzaName("NYPizza2");
}
}
public class Pizza {
private String pizzaName;
public String getPizzaName() {
return pizzaName;
}
public void setPizzaName(String pizzaName) {
this.pizzaName = pizzaName;
}
public void prepare(){
System.out.println("准备:"+ pizzaName);
}
public void bake(){
System.out.println("烘烤......");
}
public void cut(){
System.out.println("切片.....");
}
public void box(){
System.out.println("装盒.......");
}
}
public class ChicagoPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equals("ChicagoPizza1")){
pizza = new ChicagoPizza1();
}
return pizza;
}
}
public class NYPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equals("NY1")){
pizza = new NYPizza1();
}else if(type.equals("NY2")){
pizza = new NYPizza2();
}
return pizza;
}
}
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza = createPizza(type);
assert pizza != null;
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
protected abstract Pizza createPizza(String type);
}
public class MainTest {
public static void main(String[] args) {
PizzaStore pizzaStore1 = new NYPizzaStore();
pizzaStore1.orderPizza("NY1");
PizzaStore pizzaStore2 = new ChicagoPizzaStore();
pizzaStore2.orderPizza("ChicagoPizza1");
}
}