1、工厂模式
当client不知道要创建哪一个具体类的实例,或者不想在client代码中指明要具体创建的实例;换句话说就是计划在不同条件下创建不同的实例。在这种情况下,适合使用个工厂模式。
工厂模式可以视作是一个虚拟的构造器,主要思路是定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂模式的大致框架如下:(其中不同的Concrete为不同的构造方法,Product为具体构造的实例)
//常规情况下,client直接创建实例对象
Product p=new ProductOne();
//工厂模式下
Product p=new ConcreteOne.makeObject();
1.1 具体实例
问题背景:给定一个商店Shop1和其分店Shop2,两家店铺销售的商品相同,假设为Merchandise1和Merchandise2。模拟在两家店铺购买商品。
首先创建抽象产品类和两个具体产品的子类。
abstract class Merchandise{
public abstract void show();//输出商品的相关信息
}
public class Merchandise1 extends Merchandise{//商品1
private String name;
private int num;
private double price;
...
public Merchandise1(...){//构造函数
...
}
@Override
public void show(){
System.out.println("...");//输出商品的详细信息
}
...
}
public class Merchandise2 extends Merchandise{//商品1
private String name;
private int num;
private double price;
...
public Merchandise2(...){//构造函数
...
}
@Override
public void show(){
System.out.println("...");//输出商品的详细信息
}
...
}
接下来创建商店类
abstract class Shop{//商店抽象类,定义两个抽象操作
public abstract boolean add(Merchandise m);
public abstract boolean delete(Merchandise m);
}
public class Shop1 extends Shop{//商店1
private String name;
private List<Merchandise> Merlist=new ArrayList<>();
...
@Override
public boolean add(Merchandise m){
if(Merlist.contain(m)) return false;//若已存在,添加失败
Merlist.add(m);
return true;
}
@Override
public void delete(Merchandise m){
if(!Merlist.contain(m)) return false;//若未存在,删除失败
Merlist.remove(m);
return true;
}
}
public class Shop2 extends Shop{//商店2
private String name;
private List<Merchandise> Merlist=new ArrayList<>();
...
@Override
public boolean add(Merchandise m){
if(Merlist.contain(m)) return false;
Merlist.add(m);
return true;
}
@Override
public void delete(Merchandise m){
if(!Merlist.contain(m)) return false;
Merlist.remove(m);
return true;
}
}
然后创建工厂类。
interface Factory{
public Shop CreateShop(String number);
}
public class Factory1 implements Factory{//工厂类
@Override
public Shop CreateShop(String number){
if(number.equals("1")){
return new Shop1();
}
else if(number.equals("2")){
return new Shop2();
}
...
}
...
}
除了使用接口+子类的工厂模式,还可以使用静态工厂的模式。
public class Factory1 {//工厂类
public static Shop CreateShop(String number){
if(number.equals("1")){
return new Shop1();
}
else if(number.equals("2")){
return new Shop2();
}
...
}
...
}
最后就是在client通过工厂类创建商店
public class Client{
Factory factory=new Factory().CreateShop("1");
Merchandise m1=new Merchandise1(...);
Merchandise m2=new Merchandise2(...);
factory.add(m1);
factory.delete(m2);
...
}
- 工厂模式的优点;Client想要创建一个对象,只需要知道名称即可;扩展性高,如果想增加一个产品,扩展一个工厂类就可以了;不出现产品的具体实现,符合防御型编程。
- 工厂模式的缺点;每次增加一个产品时,都需要增加一个具体类和对象实现的工厂类,使得整个系统中类的个数增加较多,也增加了对系统具体类的依赖。
2、抽象工厂模式
当一个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品时,可以使用抽象工厂模式。抽象工厂模式的大致思路是提供接口创建一组相关/相依赖的对象,且无需指明其具体类。
抽象工厂模式的大致框架:
2.1 实例
- 问题背景;两种不同的操作系统Windows和Mac OS下的不同的应用程序。
首先创建的是两个操作系统的接口和相应的具体类(两个)。
//Windows系统
public interface Windows{
public void view();//输出应用程序信息
public void modify(String s);//修改应用程序信息
...
}
public class WQQ implements Windows{//应用程序1
private version;
private name;
...
@Override
public void view(){
...
System.out.println(...);
}
@Override
public void modify(String s){
...
}
}
public class WWechat implements Windows{//应用程序二
private version;
private name;
...
@Override
public void view(){
...
System.out.println(...);
}
@Override
public void modify(String s){
...
}
}
//Mac OS 操作系统
public interface Mac{
public void view();//输出应用程序信息
public void modify(String s);//修改应用程序信息
...
}
public class MQQ implements Window Mac{//应用程序1
private version;
private name;
...
@Override
public void view(){
...
System.out.println(...);
}
@Override
public void modify(String s){
...
}
}
public class MWechat implements Mac{//应用程序二
private version;
private name;
...
@Override
public void view(){
...
System.out.println(...);
}
@Override
public void modify(String s){
...
}
}
接下来定义抽象工厂接口和具体工厂类,,具体工厂类分别是QQ和Wechat在Windows和Mac操作系统下的创建。
public interface AbstractFactory{//抽象工厂接口
public Windows CreateWindowsApp();
public Mac CreateMacApp();
}
public class Factory1{//第一个具体工厂类
public Windows CreateWindowsApp(){
return new WQQ();
}
public Mac CreateMacApp(){
return new MQQ();
}
}
public class Factory2{//第二个具体工厂类
public Windows CreateWindowsApp(){
return new WWechat();
}
public Mac CreateMacApp(){
return new MWechat();
}
}
创建一个辅助类用于delegate到抽象工厂类,最后在Client创建实例。
public class Builder{
public void build(AbstractFactory factory){
Windows windows=factory.CreateWindowsApp();
Mac mac=factory.CreateMacApp();
...
}
}
public Class Client{
Builder builder=new Builder();
AbstractFactory factory=null;
Scanner input=new Scanner(System.in);
if(input.nextLine().equals("QQ")){
factory=new Factory1();
}
else if(input.nextLine.equals("WeChat")){
factory=new Factory2();
}
...
builder.build(factory);
}
- AbstractFactory创建的不是一个完整的产品,而是一个产品族(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同产品的Object,各产品创建过程对Client可见,但搭配不能改变。
- 本质上,AbstractFactory是把多类产品的factory method组合在一起,而工厂模式的一个工厂子类只创建一类产品。
- 抽象工厂的优点;新增一种产品类时,只需增加相应的具体产品类和相应的工厂子类即可;每个具体工厂类只负责创建对应的产品,而简单工厂类存在复杂的逻辑判断;不使用静态工厂方法,可以形成继承结构。
- 抽象工厂的缺点;由于抽象工厂接口中已经确定了可以被创建的产品的集合,因此如果需要添加新产品,需要修改抽象工厂类的接口,相应地,所有工厂子类也要发生变化,比较麻烦,违法了开-闭原则。