目录
1、简单工厂
2、工厂方法
3、抽象工厂
4、原型模式
// 抽象产品
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)客户端一旦要扩展具体产品的时候,势必要修改简单工厂中的代码,这样便违反了“开闭原则”。
// 抽象产品
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、当客户端扩展新产品时,不用修改作者(源代码)的代码,只需扩展一个新工厂
疑问:工厂设计模式都依赖具体的工厂的类名,如若工厂类名被修改了,那么客户端也必需要修改,感觉又回到了原点!
解释:工厂的名字是作为对外暴露的接口,作为约定要保证工厂的名字是稳定的,可能会改变但改变的几率非常低,这个比具体类的改变要小得多的多。
工厂方法的缺点:
面对产品簇,使用工厂方法设计模式会造成类的爆炸式增长(每个类都必须有一个工厂).
如若只用工厂方法的设计模式,会导致工厂类大幅增加,如下例:
// 抽象产品
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)无论多少个产品等级,抽象工厂就只有一套工厂,切实的把工厂类给减少了
抽象工厂缺点:
当产品等级发生改变时(增加产品等级、删除产品等级),都要引起所有产品簇的修改,这就违反了“开闭原则”
注一:
产品等级和产品簇说明:
使用原型模式:
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出来的对象与被克隆类不是一个地址,使用的是两个空间
上述代码存在的问题:执行这条语句
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 条评论) |