目录
工厂模式是程序中常用的设计模式,今天从下面几个点记录一下学习所得
一、简单工厂模式
这里用个例子来简单说明一下。首先,我创建如下几个类
- Test.java:程序的主入口
- Animal.java:动物父类
- Chicken.java:鸡肉类,继承于Animal
- Pig.java:猪肉类,继承于Animal
- AnimalFactory:工厂类,用于创建相应的Animal子类
Animal.java
public abstract class Animal {
public float price = 0;//价格
public int total = 0;//数量
public abstract void getDetail();
}
Chicken.java
public class Chicken extends Animal {
//初始化价格及数量
public Chicken() {
price = 10;
total = 100;
}
@Override
public void getDetail() {
System.out.println("鸡肉价格:"+price+" 数量:"+total);
}
}
Pig.java
public class Pig extends Animal {
public Pig() {
price = 15;
total = 20;
}
@Override
public void getDetail() {
System.out.println("猪肉价格:"+price+" 数量:"+total);
}
}
AnimalFactory.java
public class AnimalFactory {
//创建相应的Animal子类
public static Animal getAnimal(String cls) {
if(cls.equals(Chicken.class.getSimpleName())) {
return new Chicken();
}else if(cls.equals(Pig.class.getSimpleName())){
return new Pig();
}else {
System.out.println("无此类");
return null;
}
}
}
Test.java,在主入口类中进行Chicken及Pig类,并获取相应的信息
public class Test {
public static void main(String[] args) {
Animal chicken = AnimalFactory.getAnimal(Pig.class.getSimpleName());
Animal pig = AnimalFactory.getAnimal(Chicken.class.getSimpleName());
chicken.getDetail();
pig.getDetail();
}
}
输出结果
猪肉价格:15.0 数量:20
鸡肉价格:10.0 数量:100
以上代码就是简单工厂模式,这种工厂模式的缺点很明显,AnimalFactory的拓展性不是很好,举一个例子,如果现在我要添加一个Fish.java,我需要修改AnimalFactory.java中的代码才行。
所以对AnimalFactory.java代码做如下的修改:
public class AnimalFactory {
//创建相应的Animal子类
public static Animal getAnimal(String cls) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class clazz = Class.forName(cls);
return (Animal)clazz.newInstance();
}
}
修改后的代码看似拓展性比较好,如果再次添加一个新类,并不会修改代码,但是却有一个新问题。AnimalFactory类似与一个中转站,这里面包含了对各种Animal的操作方法,比如Chicken销往北京的价格与数量和上海是不同的,所以在Chicken属性的赋值上我们要做区分,虽然我们能在Chicken.java中设置不同地区的不同属性值,但是Chicken只是bean,并不适合做这些工作;而在AnimalFactory中操作的话,会因为Aniaml种类的增多显得非常的冗余,所以使用下面介绍的一种工厂模式比较合适
二、工厂方法模式(多态工厂模式)
包括如下几个类
- Chicken,Pig,Animal
- AnimalFactory.java:抽象类
- ChickenFactory.java:Chicken的工厂类,实现AnimalFactory接口
- PigFactory.java:Pig的工厂类,实现AnimalFactory接口
我们对Chiken及Pig类的构造器进行简单的修改:
public class Chicken extends Animal {
//初始化价格及数量
public Chicken(float p,int t) {
price = p;
total = t;
}
@Override
public void getDetail() {
System.out.println("鸡肉价格:"+price+" 数量:"+total);
}
}
public class Pig extends Animal {
public Pig(float p,int t) {
price = p;
total = t;
}
@Override
public void getDetail() {
System.out.println("猪肉价格:"+price+" 数量:"+total);
}
}
AnimalFactory.java
public interface AnimalFactory {
public Animal getAnimal();
}
ChickenFactory.java
public class ChickenFactory implements AnimalFactory {
@Override
public Animal getAnimal() {
return new Chicken(10,100);
}
}
PigFactory.java
public class PigFactory implements AnimalFactory{
@Override
public Animal getAnimal() {
// TODO Auto-generated method stub
return new Pig(15,150);
}
}
在主程序Test中进行测试
public class Test {
public static void main(String[] args){
AnimalFactory chickenFactory = new ChickenFactory();
Animal chicken = chickenFactory.getAnimal();
chicken.getDetail();
AnimalFactory pigFactory = new PigFactory();
Animal pig = pigFactory.getAnimal();
pig.getDetail();
}
}
输出的结果
鸡肉价格:10.0 数量:100
猪肉价格:15.0 数量:150
如果我们需要添加一个Finish类的话,只需要创建Finish.java和FinishFactory.java即可;如果Chicken或者Pig类因为销往各地价格不同,只需要在各自的Factory中进行个性化代码添加即可,耦合性降低,代码也不会冗余
三、抽象工厂模式
我们依然以Chicken和Pig为例,Chicken,Pig可能销往北京,上海;而北京,上海既能接收Chicken,也能接收Pig。所以地点和产品更是一个产品族。我们对产品进行细化,对产品的工厂类进行细化
Animal.java:所有bean的父类
Chicken.java,Pig.java:某个产品的抽象类
BeijingChicken.java,BeijingPig.java,ShanghaiChicken.java,ShanghaiPig.java:对某个产品的具体细化
AnimalFactory:工厂类的父类
BeijingFactory.java,ShanghaiFactory.java:具体工厂类的细化
Animal.java Chicken.java Pig.java代码如下:
public interface Animal {
void getDetail();
}
public abstract class Chicken implements Animal {
public float price = 0;//价格
public int total = 0;//数量
public abstract void getDetail();
}
public abstract class Pig implements Animal {
public float price = 0;//价格
public int total = 0;//数量
public abstract void getDetail();
}
这里我将属性提到具体的产品中,因为产品的属性不一定一样;这里Chicken Pig是抽象类,通过地点来将其细化
BeijingChicken.java ShanghaiChicken.java代码如下
public class BeijingChicken extends Chicken {
public BeijingChicken(float p,int t) {
price = p;
total = t;
}
@Override
public void getDetail() {
// TODO Auto-generated method stub
System.out.println("北京鸡肉价格:"+price+" 数量:"+total);
}
}
public class ShanghaiChicken extends Chicken {
public ShanghaiChicken(float p,int t) {
price = p;
total = t;
}
@Override
public void getDetail() {
// TODO Auto-generated method stub
System.out.println("上海鸡肉价格:"+price+" 数量:"+total);
}
}
BeijngPig.java ShanghaiPig.java代码如下:
public class BeijingPig extends Pig{
public BeijingPig(float p,int t) {
price = p;
total = t;
}
@Override
public void getDetail() {
// TODO Auto-generated method stub
System.out.println("北京猪肉价格:"+price+" 数量:"+total);
}
}
public class ShanghaiPig extends Pig {
public ShanghaiPig(float p,int t) {
price = p;
total = t;
}
@Override
public void getDetail() {
// TODO Auto-generated method stub
System.out.println("上海猪肉价格:"+price+" 数量:"+total);
}
}
以上的这四个类就是具体的产品
AnimalFactory.java BeijingFactory.java ShanghaiFactory.java代码如下
public interface AnimalFactory {
public Animal getChickenDetail();
public Animal getPigDetail();
}
public class BeijingFactory implements AnimalFactory {
@Override
public Animal getChickenDetail() {
// TODO Auto-generated method stub
return new BeijingChicken(10, 100);
}
@Override
public Animal getPigDetail() {
// TODO Auto-generated method stub
return new BeijingPig(15, 150);
}
}
public class ShanghaiFactory implements AnimalFactory {
@Override
public Animal getChickenDetail() {
// TODO Auto-generated method stub
return new ShanghaiChicken(20, 120);
}
@Override
public Animal getPigDetail() {
// TODO Auto-generated method stub
return new ShanghaiPig(25, 130);
}
}
以鸡肉为例,进行测试
public class Test {
public static void main(String[] args) {
AnimalFactory beijingChickenFactory = new BeijingFactory();
BeijingChicken beijingChicken = (BeijingChicken) beijingChickenFactory.getChickenDetail();
BeijingPig beijingPig = (BeijingPig) beijingChickenFactory.getPigDetail();
beijingChicken.getDetail();
beijingPig.getDetail();
}
}
结果
北京鸡肉价格:10.0 数量:100
北京猪肉价格:15.0 数量:150
以上就是抽象工厂类的代码,这样做的好处:我如果想要添加一个深圳的地点,我只需要创建一个ShenzhenFactory.java即可,非常符合OCP原则。但是这样的模式依然有一个非常不好的缺点,就是如果我想要添加产品的话,依然需要改AnimalFactory.java中的代码