在软件设计中,我们通常是追求封装,降低耦合。开放封闭原则是符合这一设计目标的。
开放封闭原则主要体现在:
1.对扩展开放
2.对修改封闭
我们通常使用OOP中的多态和继承来实现这个目的。
场景:一个大富翁出行,他拥有很多交通工具,汽车,轮船,飞机。
简单工厂:
将交通工具抽象为一个接口或者抽象类,使实际的交通工具继承或实现它。创造一个简单工厂(我们通常称此工厂为“上帝类”,意味着任何事都需要它负责,它可能除了负责交通工具,还要负责选择着装,负责出行时间,所以这种模式破坏了开放封闭原则中的对扩展开放)
代码如下:
package SimpleFactory; public class Car implements Vehicle{ @Override public void run() { // TODO Auto-generated method stub System.out.println("汽车在地上开"); } } public class Plane implements Vehicle{ public void run() { System.out.println("飞机在天上飞"); } } public interface Vehicle { public void run(); } public class VehicleFactory { public static Vehicle createVehicle(VehicleType t) { switch (t) { case Car: return new Car(); case Plane: return new Plane(); default: return null; } } } public enum VehicleType { Car, Plane }
测试程序:
using System; using ParkFactorys; namespace Test { class Program { static void Main(string[] args) { IFactory factory = new ParkFactoryA(); IPark park=factory.CreatePark(); park.GetParkInfo(); ICar car = factory.CreateCar(); car.Run(); Console.ReadLine(); } } }
当我们有更多同一需求时,(这里指拥有更多交通工具),必须修改上帝类Vehicle.
工厂模式
对这种情况进行了改良,我们是否可以创建一个工厂接口,当我们需要添加更多的交通工具时,可以添加不同交通工具工厂来实现此接口?
代码如下:
package FactoryMethod; public class Car implements Vehicle{ @Override public void run() { // TODO Auto-generated method stub System.out.println("汽车在地上开"); } } public class Plane implements Vehicle{ public void run() { System.out.println("飞机在天上飞"); } } public class CarFactory implements IVehicleFactory{ @Override public Vehicle CreateVehicle() { // TODO Auto-generated method stub return new Car(); } } public class PlaneFactory implements IVehicleFactory{ @Override public Vehicle CreateVehicle() { // TODO Auto-generated method stub return new Plane(); } } public interface IVehicleFactory { Vehicle CreateVehicle(); } public interface Vehicle { public void run(); }
测试程序如下:
package FactoryMethod; public class Test { public static void main(String[] args) { // TODO Auto-generated method stub IVehicleFactory iv=new CarFactory(); Vehicle v=iv.CreateVehicle(); v.run(); } }
反射工厂:
反射工厂同样是针对简单工厂破坏开封原则的一种改进,使用Java的反射特性
代码如下:(Car,Plane,Vehicle类同上,这里暂不列举)
package ReflectionFactory; import java.lang.reflect.*; public class VehicleFactory { public static Vehicle CreateVehicle(String typeName) { try { Class clazz=Class.forName(typeName); try { return(Vehicle)clazz.newInstance(); } catch (InstantiationException e) { // TODO: handle exception throw new RuntimeException("实例化异常",e); }catch (IllegalAccessException e) { // TODO: handle exception throw new RuntimeException(e); } } catch (ClassNotFoundException e) { // TODO: handle exception throw new RuntimeException("这个实体类不存在",e); } } }
测试程序:
package ReflectionFactory; public class Test { public static void main(String[] args) { // TODO Auto-generated method stub Vehicle v=VehicleFactory.CreateVehicle("ReflectionFactory.Car"); v.run(); } }
抽象工厂:
场景:当这个富翁选完了交通工具,还要考虑目的地的时候,或者考虑使用什么手机,穿什么衣服的时候,换句话说,涉及多重产品时,我们必须将工厂模式进行扩展,将大富翁今天的单一工厂(选择汽车类)扩展为多重工厂(既能选择汽车,也能选择着装,手机)
代码如下:
package AbstractFactory; public interface Ball { public void play(); } public class BasketBall implements Ball{ @Override public void play() { // TODO Auto-generated method stub System.out.println("在篮球场上打篮球"); } } package AbstractFactory; public class FootBall implements Ball{ @Override public void play() { // TODO Auto-generated method stub System.out.println("在足球场上踢足球"); } } public interface Vehicle { public void run(); } public class Car implements Vehicle{ @Override public void run() { // TODO Auto-generated method stub System.out.println("汽车在地上开"); } } public class Plane implements Vehicle{ public void run() { System.out.println("飞机在天上飞"); } } public interface IFactory { Vehicle createVehicle(); Ball createBall(); } public class DefaultFactory implements IFactory{ @Override public Ball createBall() { // TODO Auto-generated method stub return new FootBall(); } @Override public Vehicle createVehicle() { // TODO Auto-generated method stub return new Car(); } }
测试程序如下:
package AbstractFactory; public class Test { public static void main(String[] args) { // TODO Auto-generated method stub IFactory ivFactory=new DefaultFactory(); Vehicle v=ivFactory.createVehicle(); Ball b=ivFactory.createBall(); v.run(); b.play(); } }
当我们既定了富翁今天必须选择交通工具,衣着,目的地三个产品线之后,多重选择工厂IFactory就不用变化,符合开封原则,不过当你需要决定另外的事务时,就必须修改Ifactory类和默认选择类,重新新建一个产品线。
个人认为没有完美匹配任何需求的设计模式,我们必须灵活运用抽象来降低耦合性和封装,尽量使程序的扩展性和封闭性更好。
以上代码经测试无误。