源码地址:https://github.com/877148107/java-design-pattern
目录
-
工厂模式说明
我们利用一个需求来对工厂模式进行分解说明:
一个披萨的项目:要便于披萨种类的扩展,要便于维护
1) 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
2) 披萨的制作有 prepare,bake, cut, box
3) 完成披萨店订购功能。
-
传统方式实现
分析:
1.整个披萨售卖制作过程:披萨由商店售卖—用户选择类型—披萨制作。,
2.披萨除了每种的原材料不一样其他的制作过程的方式都是一样,因此我们需要一个披萨的基础抽象类来包含都一样的过程,基础类抽象类需要一个抽象的原材料准备方法让子类实现这个方法去准备不一样的原材料。不同的披萨种类继承基础的抽象类实现材料准备的过程即可。
3.需要一个订购披萨的类,用户输入自己要订购的披萨种类,那么披萨开始制作。
1、UML类图
2、代码实现
1)披萨类
public abstract class Pizza {
/**
* 名称
*/
private String name;
/**
* 由于准备披萨的材料不同所以这个将这个方法给做成抽象方法让子类去实现
* 抽象方法子类实现
*/
public abstract void prepare();
public void bake(){
System.out.println(name+"制作烘烤中。。。。。。。。。。、");
}
public void cut(){
System.out.println(name+"切割中。。。。。。。。。。。。。");
}
public void box(){
System.out.println(name+"打包中。。。。。。。。。。。。。。。。");
}
public void setName(String name) {
this.name = name;
}
}
2)披萨子类:奶酪披萨、希腊披萨
public class CheesePizz extends Pizza {
@Override
public void prepare() {
System.out.println("奶酪披萨材料准备中。。。。。。。。。。。。。。。");
}
}
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("希腊披萨材料准备中。。。。。。。。。。。。。。。");
}
}
3)订购披萨
public class OrderPizza {
/**
* OrderPizza构造器
*/
public OrderPizza() {
//获取用户想要的披萨种类
String orderType = getType();
Pizza pizza;
switch (orderType){
case "greek":
pizza = new GreekPizza();
pizza.setName("希腊披萨");
this.createPizza(pizza);
break;
case "cheese":
pizza = new CheesePizz();
pizza.setName("奶酪披萨");
this.createPizza(pizza);
break;
default:
System.out.println("sorry没有这类披萨。。。。。。。。");
break;
}
}
/**
* 披萨制作过程
* @param pizza
*/
private void createPizza(Pizza pizza) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
4)商店下单披萨
public class PizzaShop {
public static void main(String[] args) {
new OrderPizza();
}
}
3、总结
优点:实现比较简单,容易理解
缺点:违反了设计模式的开闭原则(OCP原则),即对扩展开放(提供者开放),对修改关闭(使用者关闭)。
1.当我们新增一个功能的时候改动量比较大
2.OrderPizza类需要添加一个新增的业务逻辑。并且许多地方用到OrderPizza的地方都需要进行改动。
当需要新在ChinaPizza种类、多个订购披萨类、多个商店时UML类图如下:
业务量增加时逻辑显得十分混乱不利于维护
-
简单工厂(静态工厂)模式
1) 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一 个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族 中最简单实用的模式
2) 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
3) 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式
1、UML类图
2、代码实现
1)简单工厂类
public class SimpleFactory {
/**
* 根据不同的披萨类型制作不同的披萨。
* 简单工厂模式也叫静态工厂模式,将这个方法写成一个静态的方法。
* 这个类实例化后就加载这个类方法。其他类使用的时候直接用这个类的方法即可不需要new一个工厂类
* @param orderType
* @return
*/
public Pizza createPizza(String orderType){
Pizza pizza = null;
switch (orderType){
case "greek":
pizza = new GreekPizza();
pizza.setName("希腊披萨");
break;
case "cheese":
pizza = new CheesePizz();
pizza.setName("奶酪披萨");
break;
default:
break;
}
return pizza;
}
}
静态工厂
public class SimpleFactory1 {
/**
* 根据不同的披萨类型制作不同的披萨。
* 简单工厂模式也叫静态工厂模式,将这个方法写成一个静态的方法。
* 这个类实例化后就加载这个类方法。其他类使用的时候直接用这个类的方法即可不需要new一个工厂类
* @param orderType
* @return
*/
public static Pizza createPizza(String orderType){
Pizza pizza = null;
switch (orderType){
case "greek":
pizza = new GreekPizza();
pizza.setName("希腊披萨");
break;
case "cheese":
pizza = new CheesePizz();
pizza.setName("奶酪披萨");
break;
default:
break;
}
return pizza;
}
}
2)订购披萨类
public class OrderPizza {
/**
* 这里是一个聚合关系,如果要用组合关系直接使用的话new一个工厂即可
* private SimpleFactory simpleFactory = new SimpleFactory();
*/
private SimpleFactory simpleFactory;
private Pizza pizza;
public OrderPizza(SimpleFactory simpleFactory){
setFactory(simpleFactory);
}
public void setFactory(SimpleFactory simpleFactory) {
System.out.println("简单工厂模式。。。。。。。。。。。。。。。。");
//获取用户想要的披萨种类
String orderType = getType();
Pizza pizza = simpleFactory.createPizza(orderType);
if (pizza !=null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("sorry没有改种类的披萨。。。。。。。");
}
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
静态工厂订购类
public class OrderPizza1 {
/**
* 这里是一个聚合关系,如果要用组合关系直接使用的话new一个工厂即可
* private SimpleFactory simpleFactory = new SimpleFactory();
*/
public OrderPizza1(){
System.out.println("简单工厂模式。。。。。。。。。。。。。。。。");
//获取用户想要的披萨种类
String orderType = getType();
Pizza pizza = SimpleFactory1.createPizza(orderType);
if (pizza !=null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("sorry没有改种类的披萨。。。。。。。");
}
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
3)、其他类不用变更,测试改造后的结果
-
工厂方法模式
需求分析:如果每个地方都有不同的披萨种类,比如纽约、巴黎等城市都有奶酪、胡椒等口味的披萨。根据上面的简单工厂模式只需要建立不同地方的工厂类即可。而且每个订购的类都需要聚合不同的地方的工厂类,因此采用简单工厂模式后期也不利于维护。
工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
1、UML类图
2、代码实现
1)抽象订购披萨类
public abstract class OrderPizza {
/**
* 抽象方法子类实现
* @param orderType
* @return
*/
public abstract Pizza createPizza(String orderType);
public OrderPizza(){
System.out.println("工厂方法模式。。。。。。。。。。。。。。。。");
//获取用户想要的披萨种类
String orderType = getType();
Pizza pizza = createPizza(orderType);
if (pizza !=null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("sorry没有改种类的披萨。。。。。。。");
}
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
2)子类实现创建口味的过程
public class NewYorkOrderPizza extends OrderPizza {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
switch (orderType){
case "pepper":
pizza = new NewYorkPepperPizza();
pizza.setName("纽约胡椒披萨");
break;
case "cheese":
pizza = new NewYorkCheesePizz();
pizza.setName("纽约奶酪披萨");
break;
default:
break;
}
return pizza;
}
}
public class ParisOrderPizza extends OrderPizza {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
switch (orderType){
case "pepper":
pizza = new ParisPepperPizza();
pizza.setName("巴黎胡椒披萨");
break;
case "cheese":
pizza = new ParisCheesePizz();
pizza.setName("巴黎奶酪披萨");
break;
default:
break;
}
return pizza;
}
}
3)其他类见源码,测试结果如下
-
抽象工厂模式
1) 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
2) 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
3) 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
4) 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
1、UML类图
不同地方口味的Pizza继承抽象的Pizza基础类,将创建Pizza的方法抽象成接口,每个地方的工厂实现这个抽象工厂接口。每个下单类只用聚合这个抽象工厂即可。如果业务需要新增只用修改对应的提供类即可。
2、代码实现
1)抽象工厂接口
/**
* 抽象工厂接口
*/
public interface AbstractFactory {
/**
* 让子类实现
* @param orderType
* @return
*/
Pizza createPizza(String orderType);
}
2)子类实现抽象接口
public class NewYorkFactory implements AbstractFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
switch (orderType){
case "pepper":
pizza = new NewYorkPepperPizza();
pizza.setName("纽约胡椒披萨");
break;
case "cheese":
pizza = new NewYorkCheesePizz();
pizza.setName("纽约奶酪披萨");
break;
default:
break;
}
return pizza;
}
}
public class ParisFactory implements AbstractFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
switch (orderType){
case "pepper":
pizza = new ParisPepperPizza();
pizza.setName("巴黎胡椒披萨");
break;
case "cheese":
pizza = new ParisCheesePizz();
pizza.setName("巴黎奶酪披萨");
break;
default:
break;
}
return pizza;
}
}
3)订购类
public class OrderPizza {
private AbstractFactory abstractFactory;
public OrderPizza(AbstractFactory factory){
this.abstractFactory = factory;
setFactory();
}
public void setFactory(){
System.out.println("抽象工厂模式。。。。。。。。。。。。。。。。");
//获取用户想要的披萨种类
String orderType = getType();
Pizza pizza = abstractFactory.createPizza(orderType);
if (pizza !=null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("sorry没有改种类的披萨。。。。。。。");
}
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
-
JDK源码分析工厂模式
Calendar 采用了简单工厂模式,根据不同的时区返回不同的Calendar
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
-
总结
1) 工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
2)三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
3) 设计模式的依赖抽象原则
- 创建对象实例时,不要直接 new 类, 而是把这个new 类的动作放在一个工厂的方法中并返回。变量不要直接持有具体类的引用。
- 不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
- 不要覆盖基类中已经实现的方法。
持续学习更新中。。。。。。。。