[DesignPattern] 设计之禅读书笔记(二) 工厂模式
-
工厂模式
-
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclass. (定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到了子类。)
-
图例
-
通用代码
public abstract class Product { //产品类的公共方法 public void method1() { //business logic } //抽象方法 public abstract void method2(); } public class ConcreteProduct1 extends Product { public void method2(){ // business logic } } public class ConcreteProduct2 extends Product { public void method2(){ // business logic } } public abstract class Creator { /* * 创建一个一个产品对象,其输入参数类型可以自行设置 * 通常为String Enum Class等, 当然也可以为空 * public abstract
T createProduct(Class c); } public class ConcreteCreator extends Creator { public T createProduct(Class c) { Product product = null; try { product = (Product)Class.forName(c.getName().newInstance()); } catch (Exception e){} return (T)product; } } public class Client { public static void main(String[] args) { Creator creator = new ConcreteCreator(); Product product = creator.createProduct(ConcreteProduct1.class); } } -
工厂模式的优点
- 良好的封装性,代码结构清晰
- 工厂方法的扩展性非常优秀
- 屏蔽产品类
- 工厂方法模式是典型的解耦框架
-
工厂模式的使用场景
- 工厂方法模式是new一个对象的替代品,所以在所有需要的对象的地方都可以使用, 但是需要谨慎考虑是否需要增加一个工厂类进行管理,增加代码的复杂性。
- 需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
- 工厂方法模式可以在异构项目中使用。
- 可以在测试驱动开发的框架下使用
-
例子:女娲造人
//人的接口 public interface Human { public void getColor(); public void talk(); } //具体的人 public class WhiteHuman implements Human { @Override public void getColor() { System.out.println("White skin"); } @Override public void talk() { System.out.println("My skin is white"); } } public class BlackHuman implements Human { @Override public void getColor() { System.out.println("Black skin"); } @Override public void talk() { System.out.println("My skin is black"); } } public class YellowHuman implements Human { @Override public void getColor() { System.out.println("Yellow skin"); } @Override public void talk() { System.out.println("My skin is yellow"); } } //造人的抽象工厂 public abstract class AbstractHumanFactory { public abstract
T createHuman(Class c); } //具体的造人 public class HumanFactory extends AbstractHumanFactory { @Override public T createHuman(Class c) { Human human = null; try { human = (T) Class.forName(c.getName()).getDeclaredConstructor().newInstance(); } catch (Exception e) { System.out.println("Having problem when create human"); } return (T)human; } } //女娲 public class NvWa { public static void main(String[] args) { AbstractHumanFactory YinYangLu = new HumanFactory(); System.out.println("------------------------"); Human whiteHuman = YinYangLu.createHuman(WhiteHuman.class); whiteHuman.getColor(); whiteHuman.talk(); System.out.println("------------------------"); Human yellowHuman = YinYangLu.createHuman(YellowHuman.class); yellowHuman.getColor(); yellowHuman.talk(); System.out.println("------------------------"); Human blackHuman = YinYangLu.createHuman(BlackHuman.class); blackHuman.getColor(); blackHuman.talk(); } } -
-
扩展
- 简单工厂
- 一个模块如果只需要一个工厂类,没有必要把它生产出来, 使用静态的方法就可以了
- 对于上面的例子来说,去掉abstractHumanFacotry, 同时把createHuman方法设置成静态类。
- 在实际项目中,采用该方法的案例还是比较多的, 优点是比较简单,缺点是工厂类扩展比较困难, 不符合开闭原则, 但它仍然是一个很实用的设计模式。
- 例子
public class HumanFactory { public static
T createHuman(Class c) { Human human = null; try { human = (T) Class.forName(c.getName()).getDeclaredConstructor().newInstance(); } catch (Exception e) { System.out.println("Having problem when create human"); } return (T) human; } } public class NvWa { public static void main(String[] args) { System.out.println("------------------------"); Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class); whiteHuman.getColor(); whiteHuman.talk(); System.out.println("------------------------"); Human yellowHuman = HumanFactory.createHuman(YellowHuman.class); yellowHuman.getColor(); yellowHuman.talk(); System.out.println("------------------------"); Human blackHuman = HumanFactory.createHuman(BlackHuman.class); blackHuman.getColor(); blackHuman.talk(); } } - 升级为多个工厂类
- 具体的产品类都对应了一个创造者, 每个创建者都独立船舰对应的产品对象,非常符合单一职责原则
- 更改上面的例子,对每个不同肤色的人都有自己的工厂,同时因为每个工厂负责自己创建相关类,所以抽象工厂不再需要传递参数。
- 例子
public abstract class AbstractHumanFactory { public abstract Human createHuman(); } public class BlackHumanFactory extends AbstractHumanFactory { @Override public Human createHuman() { return new BlackHuman(); } } public class WhiteHumanFactory extends AbstractHumanFactory { @Override public Human createHuman() { return new WhiteHuman(); } } public class YellowHumanFactory extends AbstractHumanFactory { @Override public Human createHuman() { return new YellowHuman(); } } public class NvWa { public static void main(String[] args) { System.out.println("------------------------"); Human whiteHuman = (new WhiteHumanFactory()).createHuman(); whiteHuman.getColor(); whiteHuman.talk(); System.out.println("------------------------"); Human yellowHuman = (new YellowHumanFactory()).createHuman(); yellowHuman.getColor(); yellowHuman.talk(); System.out.println("------------------------"); Human blackHuman = (new BlackHumanFactory()).createHuman(); blackHuman.getColor(); blackHuman.talk(); } }
- 替代单例模式
- 可以代替单例,但是觉得没啥必要
- 例子
public class Singleton { private Singleton(){} public void doSomething(){} } public class SingletonFactory { private static Singleton singleton; static { try { Class cl = Class.forName(Singleton.class.getName()); Constructor constructor = cl.getDeclaredConstructor(); constructor.setAccessible(true); singleton = (Singleton)constructor.newInstance(); } catch (Exception e) { } } public static Singleton getSingleton() { return singleton; } }
- 延迟初始化(Lazy initialization)
- 一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。
- 延迟加载框架是可以扩展的,例如限制某一个产品的最大实例化数量。
- 图示
- 例子
public class ProductFactory { private static final Map
prMap = new HashMap(); public static synchronized Product createProduct(String Type) throws Exception { Product product = null; if (prMap.containsKey(type)) { product = preMap.get(type); } else { if (type.equals("Product1")) { product = new ConcreteProduct1(); } else { product = new ConcreteProduct2(); } prMap.put(type.product); } } return product; }
- 简单工厂
-