看一个披萨的项目:
需求点: 要便于披萨种类的扩展, 要便于维护
package com.dance.design.designmodel.factory.simple;
public class CtPizz {
public static void main(String[] args) {
OrderPizza.ding("ce");
OrderPizza.ding("ge");
}
}
/**
* 披萨类
*/
abstract class Pizza{
/**
* 名称
*/
public String name;
/**
* 准备材料
*/
public abstract void prepare();
/**
* 为了不每次都全部调用, 我创建一个构建披萨的方法
*/
public void buildPizza(){
prepare();
bake();
cut();
box();
}
/**
* 烘烤
*/
public void bake(){
System.out.println(name + "baking ...");
}
/**
* 切块
*/
public void cut(){
System.out.println(name + "cutting ...");
}
/**
* 打包
*/
public void box(){
System.out.println(name + "boxing ...");
}
}
/**
* 奶酪披萨
*/
class CePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备奶酪披萨的原材料");
name = "奶酪披萨";
}
}
/**
* 希腊披萨
*/
class GePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备希腊披萨的原材料");
name = "希腊披萨";
}
}
/**
* 订购类
*/
class OrderPizza{
public OrderPizza(){}
public static void ding(String orderType){
Pizza pizza = null;
if("ce".equals(orderType)){
pizza = new CePizza();
}else if("ge".equals(orderType)){
pizza = new GePizza();
}else{
throw new RuntimeException("订单类型错误");
}
// 开始制作
pizza.buildPizza();
}
}
我这里没有写设么用户输入啥的,应为感觉意义不大, 我们主要看设计模式,而不是关注其他的边缘细节
我们需要新增一种Pizza, 我们就需要创建新的Pizza种类 ,然后修改订单类的判断逻辑, 当然, 如果在别处还有创建的话, 需要在别处也修改, 这样的话改动量就会比较大
我们新增巧克力披萨
/**
* 巧克力披萨
*/
class QkPizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备巧克力披萨的原材料");
name = "巧克力披萨";
}
}
修改OrderPizza逻辑, 这个创建的逻辑可能在很多地方都有,所以需要都修改, 我们这里只有一种效果看着还不是很麻烦
增加调用逻辑
到此扩展完毕, 应为设计的原因披萨类型扩展很容易, 调用扩展是必须的, 但是中间部分如果很多的话, 其实是可以统一管理的, 还有就是对于OrderPizza来说, 它其实是不应该知道Pizza的创建逻辑的, 而且如果后续扩展门店的话
会有orderPizza2, orderPizza3, 这样每个类都会和Pizza,Ce.., Ge.. Qk..全部发生关系, 如果一旦再增加Pizza的种类, 就会改动量非常大
把创建具体披萨的任务交给工厂, 这样我们创建的时候, 只需要调用工厂的方法即可, 其调用工厂的地方是不需要修改的
这样, 我让我的订单去面对工厂, 后续改造仅限于工厂, 种类, 和调用方, 但是订单是不需要修改的, 哪怕后续扩展订单门店, 也是直接面对工厂就可以了, 不必关注细节
增加工厂类
class PizzaFactory{
public static Pizza createPizza(String orderType){
Pizza pizza = null;
if("ce".equals(orderType)){
pizza = new CePizza();
}else if("qk".equals(orderType)){
pizza = new QkPizza();
}else if("ge".equals(orderType)){
pizza = new GePizza();
}else{
throw new RuntimeException("订单类型错误");
}
return pizza;
}
}
修改OrderPizza
/**
* 订购类
*/
class OrderPizza{
public OrderPizza(){}
public static void ding(String orderType){
// 开始制作
PizzaFactory.createPizza(orderType).buildPizza();
}
}
后续种类再则么多, 我的订单类都是不用动的
我们的披萨店越做越大, 终于,在不同的地区开分店了,比如北京, 上海,广州等, 这个时候顾客就可以在不同的地区点北京的奶酪披萨, 上海的藤椒披萨等
使用简单工厂模式, 我们可以创建BJPizzaFactory, SHPizzaFactory等, 从这案例来说是可以的, 但是考虑项目的规模,以为软件的可维护性和可扩展性并不是特别好, 所以我们用工厂方法模式
工厂方法设计方案: 将披萨项目的实例化功能抽象成抽象方法, 在不同的口味点餐子类中做具体实现
工厂方法模式: 定义了一个创建对象的抽象方法, 由子类决定要实例化的类, 工厂方法模式将对象的实例化推迟到子类
package com.dance.design.designmodel.factory.simple.sp3;
import com.sun.org.apache.xpath.internal.operations.Or;
public class CtPizz {
public static void main(String[] args) {
new BJOrderPizza().ding("ce");
new BJOrderPizza().ding("ge");
new SHOrderPizza().ding("ce");
new SHOrderPizza().ding("ge");
}
}
/**
* 披萨类
*/
abstract class Pizza{
/**
* 名称
*/
public String name;
/**
* 准备材料
*/
public abstract void prepare();
/**
* 为了不每次都全部调用, 我创建一个构建披萨的方法
*/
public void buildPizza(){
prepare();
bake();
cut();
box();
}
/**
* 烘烤
*/
public void bake(){
System.out.println(name + "baking ...");
}
/**
* 切块
*/
public void cut(){
System.out.println(name + "cutting ...");
}
/**
* 打包
*/
public void box(){
System.out.println(name + "boxing ...");
}
}
/**
* 北京奶酪披萨
*/
class BJCePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备北京奶酪披萨的原材料");
name = "北京奶酪披萨";
}
}
/**
* 上海奶酪披萨
*/
class SHCePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备上海奶酪披萨的原材料");
name = "上海奶酪披萨";
}
}
/**
* 希腊披萨
*/
class BJGePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备北京希腊披萨的原材料");
name = "北京希腊披萨";
}
}
/**
* 希腊披萨
*/
class SHGePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备上海希腊披萨的原材料");
name = "上海希腊披萨";
}
}
/**
* 订购类
*/
abstract class OrderPizza{
public OrderPizza(){}
public abstract void ding(String orderType);
}
/**
* 北京店
*/
class BJOrderPizza extends OrderPizza {
@Override
public void ding(String orderType) {
Pizza pizza = null;
if("ce".equals(orderType)){
pizza = new BJCePizza();
}else if("ge".equals(orderType)){
pizza = new BJCePizza();
}else{
throw new RuntimeException("订单类型错误");
}
// 开始制作
pizza.buildPizza();
}
}
/**
* 上海店
*/
class SHOrderPizza extends OrderPizza {
@Override
public void ding(String orderType) {
Pizza pizza = null;
if("ce".equals(orderType)){
pizza = new SHCePizza();
}else if("ge".equals(orderType)){
pizza = new SHCePizza();
}else{
throw new RuntimeException("订单类型错误");
}
// 开始制作
pizza.buildPizza();
}
}
这样我们调用只针对与门店, 上海调用上海的门店, 北京调用北京的门店, 然后由门店去面对Pizza和子类, 但是我感觉这样也不太好, 接下来使用抽象工厂改造~
订单抽象类, 面向 抽象工厂, 抽象工厂面向披萨抽象类, 细节由实现类去维护
package com.dance.design.designmodel.factory.simple.sp3;
public class CtPizz {
public static void main(String[] args) {
new BJOrderPizza(new BJPizzaFactory()).ding("ce");
new BJOrderPizza(new BJPizzaFactory()).ding("ge");
new SHOrderPizza(new SHPizzaFactory()).ding("ce");
new SHOrderPizza(new SHPizzaFactory()).ding("ge");
}
}
/**
* 披萨类
*/
abstract class Pizza{
public String name;
public abstract void prepare();
public void buildPizza(){
prepare();
bake();
cut();
box();
}
public void bake(){
System.out.println(name + "baking ...");
}
public void cut(){
System.out.println(name + "cutting ...");
}
public void box(){
System.out.println(name + "boxing ...");
}
}
/**
* 北京奶酪披萨
*/
class BJCePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备北京奶酪披萨的原材料");
name = "北京奶酪披萨";
}
}
/**
* 上海奶酪披萨
*/
class SHCePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备上海奶酪披萨的原材料");
name = "上海奶酪披萨";
}
}
/**
* 北京希腊披萨
*/
class BJGePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备北京希腊披萨的原材料");
name = "北京希腊披萨";
}
}
/**
* 上海希腊披萨
*/
class SHGePizza extends Pizza{
@Override
public void prepare() {
System.out.println("准备上海希腊披萨的原材料");
name = "上海希腊披萨";
}
}
/**
* 订购类
*/
abstract class OrderPizza{
/**
* 面对抽象工厂
*/
protected AbsPizzaFactory pizzaFactory;
public OrderPizza(AbsPizzaFactory pizzaFactory){
this.pizzaFactory = pizzaFactory;
}
public void ding(String orderType){
// 默认逻辑
pizzaFactory.createPizza(orderType).buildPizza();
}
}
/**
* 抽象工厂
*/
abstract class AbsPizzaFactory{
protected abstract Pizza createPizza(String orderType);
}
/**
* 北京披萨工厂
*/
class BJPizzaFactory extends AbsPizzaFactory{
@Override
protected Pizza createPizza(String orderType) {
Pizza pizza = null;
if("ce".equals(orderType)){
pizza = new BJCePizza();
}else if("ge".equals(orderType)){
pizza = new BJCePizza();
}else{
throw new RuntimeException("订单类型错误");
}
return pizza;
}
}
/**
* 上海披萨工厂
*/
class SHPizzaFactory extends AbsPizzaFactory{
@Override
protected Pizza createPizza(String orderType) {
Pizza pizza = null;
if("ce".equals(orderType)){
pizza = new SHCePizza();
}else if("ge".equals(orderType)){
pizza = new SHCePizza();
}else{
throw new RuntimeException("订单类型错误");
}
return pizza;
}
}
/**
* 北京店
*/
class BJOrderPizza extends OrderPizza {
public BJOrderPizza(AbsPizzaFactory pizzaFactory) {
super(pizzaFactory);
}
}
/**
* 上海店
*/
class SHOrderPizza extends OrderPizza {
public SHOrderPizza(AbsPizzaFactory pizzaFactory) {
super(pizzaFactory);
}
}
其实抽象工厂我感觉还可以改进一下, 这样的话调用方就知道了具体的类,如果调用方多的话也不好维护, 可以再提供一个工厂创建者的单利, 通过传入地区也就是BJ, SH来获取一个抽象工厂(都已经学过单利模式了吧), 这个就自己去改造吧
public class CalendarTest {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
System.out.println("年:" + calendar.get(Calendar.YEAR));
// 月从0 开始 需要 +1
System.out.println("月:" + (calendar.get(Calendar.MONTH)+ 1));
System.out.println("日:" + calendar.get(Calendar.DAY_OF_MONTH));
System.out.println("时:" + calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("分:" + calendar.get(Calendar.MINUTE));
System.out.println("秒:" + calendar.get(Calendar.SECOND));
}
}
如何,有感受到简单工厂的气息吗? 当然不只是简单工厂, 从第一行getInstance中也感受出来了吧, 这还是一个单利, 当然如果看源码的的话, 你就感受到很多其他的设计模式, 由此可以看出大佬是多么的**
emm, 源码就不看了, 从使用上感受一下就可以了, 额, 要不还是看一下吧
public static Calendar getInstance(TimeZone zone,Locale aLocale){
return createCalendar(zone, aLocale);
}
getInstance调用了createCalendar
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;
}
好了看完了吧
将实例化细节的代码提取出来, 放到工厂类中统一管理和维护,达到和主业务线的依赖关系的解耦,从而提高了项目的扩展和维护性