设计模式(一)——工厂模式、原型模式

阅读: 评论:0

设计模式(一)——工厂模式、原型模式

设计模式(一)——工厂模式、原型模式

目录

 

1、简单工厂

 2、工厂方法

3、抽象工厂

4、原型模式


1、简单工厂

// 抽象产品
interface Food {void eat();
}
// 具体产品
class Hamburger implements Food {@Overridepublic void eat() {System.out.println("吃汉堡!");}
}
public class Test {public static void main(String[] args) {Food f = new Hamburger();f.eat();}
}

这种设计,一旦修改了具体产品的类名,客户端代码也要随之一起改变,这样服务端和客户端就是耦合的。

新增一个简单工厂处理;

class FoodFactory {public static Food getFood(int n) {Food food = null;switch (n) {case 1:food = new Hamburger();break;case 2:food = new Rice();break;}return food;}
}
public class Test {public static void main(String[] args) {Food f = Food(1);f.eat();}
}

优点:

1)把具体产品的类型,从客户端代码中解耦出来

2)服务器端,如果修改了具体产品的类名,客户端也知道

缺点:

1)客户端需要记住常量与具体产品的映射关系,如:1 -> 汉堡

2)如果具体产品特别多,简单工厂将变得十分臃肿

3)客户端一旦要扩展具体产品的时候,势必要修改简单工厂中的代码,这样便违反了“开闭原则”。 

 2、工厂方法

// 抽象产品
interface Food {void eat();
}
// 具体产品
class Hamburger implements Food {@Overridepublic void eat() {System.out.println("吃汉堡!");}
}
class Rice implements Food {@Overridepublic void eat() {System.out.println("吃面!");}
}
interface FoodFactory {public Food getFood();
}
class HamburgerFactory implements FoodFactory {@Overridepublic Food getFood() {return new Hamburger();}
}
class RiceFactory implements FoodFactory {@Overridepublic Food getFood() {return new Rice();}
}

工厂方法的UML类图: 

工厂方法的优点:

1、仍然具有简单工厂的优点

2、当客户端扩展新产品时,不用修改作者(源代码)的代码,只需扩展一个新工厂

 疑问:工厂设计模式都依赖具体的工厂的类名,如若工厂类名被修改了,那么客户端也必需要修改,感觉又回到了原点!

解释:工厂的名字是作为对外暴露的接口,作为约定要保证工厂的名字是稳定的,可能会改变但改变的几率非常低,这个比具体类的改变要小得多的多。

 工厂方法的缺点:

面对产品簇,使用工厂方法设计模式会造成类的爆炸式增长(每个类都必须有一个工厂).

3、抽象工厂

如若只用工厂方法的设计模式,会导致工厂类大幅增加,如下例:

// 抽象产品
interface Food {void eat();
}
// 具体产品
class Hamburger implements Food {@Overridepublic void eat() {System.out.println("吃汉堡!");}
}
class Rice implements Food {@Overridepublic void eat() {System.out.println("吃面!");}
}
// 抽象产品
interface Drink {public void drink();
}
// 具体产品
class Cola implements Drink {@Overridepublic void drink() {System.out.println("喝可乐!");}
}
class IcePeak implements Drink {@Overridepublic void drink() {System.out.println("喝冰峰!");}
}
// 工厂
interface DrinkFactory {public Drink getDrink();
}
class ColaFactory implements DrinkFactory {@Overridepublic Drink getDrink() {return new Cola();}
}
class IcePeakFactory implements DrinkFactory {@Overridepublic Drink getDrink() {return new IcePeak();}
}
interface FoodFactory {public Food getFood();
}
class HamburgerFactory implements FoodFactory {@Overridepublic Food getFood() {return new Hamburger();}
}
class RiceFactory implements FoodFactory {@Overridepublic Food getFood() {return new Rice();}
}

 使用抽象工厂:

// 抽象产品
interface Drink {public void drink();
}
// 具体产品
class Cola implements Drink {@Overridepublic void drink() {System.out.println("喝可乐!");}
}
class IcePeak implements Drink {@Overridepublic void drink() {System.out.println("喝冰峰!");}
}
// 工厂
interface Factory {public Food getFood();public Drink getDrink();
}
class KFCFactory implements Factory {@Overridepublic Food getFood() {return new Hamburger();}@Overridepublic Drink getDrink() {return new Cola();}
}
class DongFactory implements Factory {@Overridepublic Food getFood() {return new Rice();}@Overridepublic Drink getDrink() {return new IcePeak();}
}

抽象工厂优点:

1)具有简单工厂、工厂方法的优点

2)无论多少个产品等级,抽象工厂就只有一套工厂,切实的把工厂类给减少了

 抽象工厂缺点:

当产品等级发生改变时(增加产品等级、删除产品等级),都要引起所有产品簇的修改,这就违反了“开闭原则”

注一:

产品等级和产品簇说明:

4、原型模式

使用原型模式: 

1)必须让目标类实现Cloneable接口,改接口没有任何抽象方法,仅仅是一个标记接口。表示实现该接口的类可以被克隆
2)必须重写java.long.Object类的clone方法,将返回权限改为public

 测试用例:

class WeekReport implements Cloneable {private int id;private String emp;private String summary;private String plain;private String suggestion;private Date time;
......@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws Exception {WeekReport wr = new WeekReport();wr.setEmp("张三");wr.setSummary("完成4篇推文");wr.setPlain("推送一篇原创文章");wr.setSuggestion("无");wr.setTime(new Date());// 入库,用输出测试System.out.println(wr);WeekReport wr2 = (WeekReport) wr.clone();wr2.setSummary("完成一篇原创文章");wr2.setSummary("3篇推文");System.out.println(wr2);}
}

 

 注:

1)clone方法不会调用构造器,是直接复制内存中的2进制

2)clone出来的对象与被克隆类不是一个地址,使用的是两个空间

上述代码存在的问题:执行这条语句  这时会导致wr对象的time属性也会发生改变,这是由浅拷贝所导致的。解决方案:

    public Object clone() throws CloneNotSupportedException {WeekReport weekReport = (WeekReport) super.clone();Date clone = (Date) Time().clone();weekReport.setTime(clone);return weekReport;}

但该方案还是有问题,如果该属性是一个对象,对象里面还包含有其他对象,那么这种嵌套将无止境,无法实现克隆功能。解决方案:

使用Serializable接口:

class WeekReport implements Cloneable, Serializable {}

修改clone方法:

public Object clone() throws CloneNotSupportedException {try {ByteArrayOutputStream out = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(out);oos.writeObject(this);oos.close();// 从内存中读取数据byte[] bytes = ByteArray();InputStream in = new ByteArrayInputStream(bytes);ObjectInputStream ois = new ObjectInputStream(in);Object clone = adObject();ois.close();return clone;} catch (Exception e) {throw new RuntimeException(e);}
}

本文发布于:2024-01-28 10:40:52,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17064096586840.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:模式   原型   工厂
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23