脚本宝典收集整理的这篇文章主要介绍了一. 抽象工厂&工厂方法&简单工厂方法,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
参考《大话设计模式》第十五章
用户可能用两种类型的数据库,这两种数据库有类似的方法,但如果一开始声明对象时,固定了它使用 SQL Server 数据库F1a;SqlserverUser su=new SqlserverUser()
,那么要是后面需要改成Access数据库,它调用的各种方法都需要改变,需要修改的代码量很大。比如添加用户操作:su.Insert(User),两种类型的数据库都是执行这个操作,但具体实现的代码不同,这样需要全部改变。 此问题的特点:有多种模式可以用,但不同模式又有相似操作。虽然不同模式实现相似操作的具体代码不同,但对用户来说达到的效果是一样的。
定义:抽象工厂模式——提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
UML图 对上述问题的解决方法: 对用户来说:他只看得到抽象接口IUser,不用知道具体实现类(SqlserverUser和AccesSUSEr)。这意味着他知道有哪些操作(IUer告诉他的),但不用考虑是在Sqlserver还是Access的环境中使用操作。那么当要从Sqlserver数据库改到Access数据库时,只要改变传给工厂的指令,但用户端的操作代码都不用变(操作是固定的,IUser中定义了固定的操作)。 对工厂来说:首先告诉工厂是在哪个环境,工厂根据指定的环境创造具体工厂(不同的具体工厂会创造不同的操作组合)。然后具体工厂将这些操作组合在一起,返回给用户。这样用户不用去挑选环境对应的各个操作,直接从工厂那里拿到一整套的操作。
代码
IUser和IDocument
interface IUser//定义了关于User的操作
{
void Insert(User user);
User GetUser(int id);
}
interface IDepartment//定义了关于department的操作
{
void Insert(Department department);
Department GetDepartment(int id);
}
IUser和IDepartment的具体实现类:
//SqlserverUser,用于访问 SQL Server 的 User
class SqlserverUser implements Iuser
{
public void Insert(User user)
{
...
}
public void GetUser(int id)
{
...
}
}
//AccessUser,用于访问Access 的 User
class AccessUser implements Iuser
{
public void Insert(User user)
{
...
}
public void GetUser(int id)
{
...
}
}
//SqlserverDepartment,用于访问 SQL Server 的 Department
class SqIserverDepartment implements IDepartment
{
...
}
//AcceSSDepartment,用于访问Access 的 Department
class AccessrDepartment implements IDepartment
{
...
}
IFactory接口
interface IFactory
{
IUser CreateUser();
}
IFactory的具体实现类
//SqlServerFactory类
class SqlServerFactory implements IFactory
{
public IUser CreateUser()
{
return new SqlserverUser();
}
public IDocument CreateDocument()
{
return new SqlserverDocument();
}
}
//AccessFactory类
class AccessFactory implements IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
public IDocument CreateDocument()
{
return new AccessDcocument();
}
}
客户端代码
static void Main(string[] args)
{
IFactory factory=new SqlServerFactory();//选择创造具体产品组合的具体工厂
IUser iu = factory.CreateUser();//通过具体子类创造产品
IDocument idoc = factory.CreateDocument();
User user=new User();
Document document=new Document();
iu.Insert(user);
iu.GetUser(1);
idoc.Insert(document);
idoc.GetDocument(1);
}
优点
易于交换产品系列。由于选择具体工厂类(如 IFactory factory=new AccessFactory() )只需要在初始化的时候出现—次,这就使得改变—个应用的操作环境很容易。只用改变这一条指令,指定不同的具体工厂就可以改变操作环境。
让具体的创建实例过程与客户端分离。客户端只知道有抽象类 IUser 和IDepartment,抽象类告诉用户有哪些操作,而具体产品类的代码不会出现在客户端代码中。
缺点:
如果后期要增加产品——项目表PROIect(PRoject和User、Department同级)需要做以下改动:
(1)增加抽象接口IProject,以及增加IProject的具体实现类 SqlserverProject、AccessProject
(2)还需要更改抽象工厂接口IFactory,以及更改具体工厂SqlserverFactory和 AccessFactory 这也比较繁琐,这个问题可以用简单工厂解决,将抽象工厂和具体工厂统一成一个工厂DateAccess(如下图),这样就只用增加(1),以及在DataAccess里增加一个方法:CreateProject()。简单工厂在后文详述。
如果客户端程序有很多,每个客户端都有IFactory factory=new SqlserverFactory,当要换成Access数据库时,每个客户端都需要改变:IFactory factory=new AccessFactory()。这并没有实现我们的需求:只改一处,而所有的客户端都能变。但是这个问题可以通过反射解决。
还没仔细了解反射,这部分请跳过,复习javase后补充。
常规抽象工厂的写法 :IUser result = new SqlserverUser();
反射的写法:using System.Reflection;先引用System.Reflection 的命名空间 IUser result=(IUser)AsSEMbly.Load(“抽 象 工厂模式”).Createinstance(“抽 象 工.厂模式. SqlserverUser”); 当前"命名空间"名称要实例化的"类名" 当前"程序集"的名称
参考:《大话设计模式》第一章
从固定的印刷到活字印刷体现了面向对象的好处:通过封装、继承、多态把程序的耦合性降低
第一,要改印刷模板,只需更改对应的字,而不是重新印刷整个产品,此为可维护;
第二,印刷用到的模板字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;
第三,印刷模板若要加字,只需另刻字加入即可,这是可扩展;
第四字的排列其实可能是睡排可能是横排,此时只需将活字移动就可,做到满足排列需求,此是灵活性好;
此章面对的问题:计算器实现+-*/,这几个运算有相似和不同的部分,如果没有分离开,当我们要增加一个运算,或者给这几个类都增加一个功能,改动很大。所以采用封装实现低耦合,具体见下。
封装:就是让业务逻辑与界面逻辑分开,让它们之间的耦合度下降。业务逻辑是工厂和运算类来完成(比如工厂可以选择实现哪个具体运算,运算类可以进行具体操作),界面逻辑是客户端代码完成。只有分离开,才可以达到容易维护或扩展。
“+”、“-”、“*”、"/"算法也要分开,用一个抽象类(下面UML图中的“运算类”)来实现抽象步骤,而具体类(下面的加法类、乘法类…)来选择具体用哪个算法。
到底要实例化谁,将来会不会增加实例化的对象,比如增加开根运算——这是很容易变化的地方,应该考虑用一个単独的类(简单工厂类)来做这个创造实例的过程,这就是工厂。
这里工厂不是抽象的,它通过输入创造了类。
public class SimpleFacory//简单工厂类
{
public static operation createOprate(String OPErate)
{
Operation opr=null;
swITch(opr)
{
case "+":
opr=new OperationAdd();
break;
case "-":
opr=new OperationSub();
break;
case "*":
opr=new OperationMul();
break;
case "/":
opr=new OperationDiv();
break;
}
return opr;
}
}
Operation opr;
//例如想进行加法运算
opr=SimpleFactory.createOperate("+");//利用了多态性
//下面的属性和方法是抽象类固定的,具体选择哪个子类是由上面SimpleFactory决定的。
opr.NumberA=1;
opr.NumberB=2;
double result=opr.GetResult();
参考《大话设计模式》第八章
工厂方法模式是定义一个用于创建对象的接口(IFactory),让子类(这里指的是工厂接口的子类,即具体工厂)决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
和 3.简单工厂模式 面对的问题一样,即对+ - * / 类的分离和封装。但这里,具体选择哪个类不是在工厂内决定,而是用户端决定。即switch case
不是在工厂内部了,而是在客户端代码,这样更能体现封闭性,后面会具体分析。
抽象工厂代码:
interface IFactory//抽象工厂是一个接口,需要子类实现接口,而不能直接调用方法
{
Operation CreateOperation();//所有具体工厂都有这个方法。
}
具体工厂的代码:
class AdDFactory implements IFactory
{
public Operation CrateOperation()
{
return new OperationAdd();//OperationAdd是Operation的子类,利用了多态性
}
}
class SubFactory implements IFactory
{
public Operation CrateOperation()
{
return new OperationAdd();//OperationSub是Operation的子类,利用了多态性
}
}
class MulFactory implements IFactory
{
public Operation CrateOperation()
{
return new OperationAdd();//OperationMul是Operation的子类,利用了多态性
}
}
class DivFactory implements IFactory
{
public Operation CrateOperation()
{
return new OperationAdd();//OperationDiv是Operation的子类,利用了多态性
}
}
客户端代码:
IFactory oprFactory=new AddFactory();//例如想要实现加法类,这里是在客户端选择具体工厂,也可以用case,根据一个变量来选择具体工厂
Operation opr=oprFactory.CreateOperation();//这里得到的就是加法具体类了
opr.NumberA=1;
opr.NumberB=2;
double result=opr.GetResult();
对比二者的UML图,发现工厂方法多出来的是:四个具体工厂的分支去和具体运算类耦合,而简单工厂是一个工厂直接和四个具体运算类耦合。那么工厂方法的好处是什么呢?
考虑我们要增加一个运算:求 M N M^N MN,
在简单工厂类中,我们需要改变简单工厂:如图,在它 createOprate()方法内部增加一个case "^"
,这样才可以选择乘方运算。但这种对类的改变会破坏封闭原则,我们希望封装好的类不再做改变。
在工厂方法中,我们只用再增加一个具体工厂:
class PowerFactory implements IFactory
{
public Operation CrateOperation()
{
return new OperationPower();
}
}
如图:
这样既扩展了抽象工厂,又没有改变抽象工厂内部代码。其实这本质上是把switch case
交给了客户端代码,这样就会增加客户端代码的改动。
switch case
(选择实例化哪个具体运算类)是工厂来做的。所以,对于客户端来说,去除了与具体产品的依赖,客户不用做逻辑判断。客户不用知道有哪些具体工厂,他只知道“+”这个字符。 我们可以对比一下二者客户端的代码: //简单工厂:只用给简单工厂(SimpleFactory)一个字符“+”,就能得到想要的具体加法类。
Operation opr;
opr=SimpleFactory.createOperate("+");//给简单工厂一个字符“+”,返回了具体的加法类
opr.NumberA=1;//然后利用加法类得到结果
opr.NumberB=2;
double result=opr.GetResult();
//工厂方法:客户端需要选择具体工厂AddFactory,
// 如果想要选择不同的具体工厂,可以加上switch case。
// 所以这里是把逻辑判断(选择哪个工厂)交给了用户,
// 而简单工厂中是SimpleFactory来进行逻辑判断的
IFactory oprFactory=new AddFactory();//客户端选择具体工厂
Operation opr=oprFactory.CreateOperation();//再利用具体工厂得到想要的加法类
opr.NumberA=1;//然后利用加法类得到结果
opr.NumberB=2;
double result=opr.GetResult()
结构图对比
抽象工厂:
工厂方法:
可见二者都有抽象工厂、具体工厂,抽象产品、具体产品,并且是具体工厂和具体产品耦合。 但是工厂方法中只有一个抽象产品,每个具体工厂和一个抽象产品的具体产品耦合; 抽象工厂有多个抽象产品,每个具体工厂和多个抽象产品的具体产品耦合,并且将不同具体产品进行组合。抽象工厂是工厂方法的扩展。以上是脚本宝典为你收集整理的一. 抽象工厂&工厂方法&简单工厂方法全部内容,希望文章能够帮你解决一. 抽象工厂&工厂方法&简单工厂方法所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。