【笔记】大话设计模式-11-13
文章目录
11 迪米特法则
11.1 Example
举个例子: 阿三现在在一家汽车公司做软件开发,汽车上装载了一些传感器,需要采集人员采集一些数据回来测试。以前,阿三都是直接联系数据采集部门的大头帮忙的,今天大头请假了,阿三就感觉找不到人了。
其实,应该建立一个数据采集平台,阿三直接在平台上提出需求,然后数据采集部门接收到该请求,把这个人物分配给部门内的采集人员即可,不用必须指定大头,降低部门人员之间的耦合性,提高效率。
11.2 定义
迪米特法则(LoD)
:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法,可以通过第三者转发这个调用。
11.3 总结
-
在类的结构设计上,每一个类都应当尽量降低成员的访问权限,每个类包装好自己的privite状态,不需要公开的就不要公开;
-
迪米特法则根本思想,就是强调类之间的松耦合,耦合越弱,越有利于复用,一个处于弱耦合的类被修改,不会对有关系的类造成波及。
信息的隐藏促进了软件的复用
。 -
对于一个组织也是一样的,人员之间的耦合性越弱,越有利于组织的健康发展和良性循环。耦合性越强,越容易滋生腐败。
12 外观模式
12.1 Example
阿三最近看同事们都在炒股玩基金,也想参与进去。可是股票呢,得要随时关注,投资者与股票的联系比较大,造成波动性比较大,对于钱包发紧的阿三来说,代价比较大,这是耦合性过高
造成的。
调查一波发现,基金的稳定性比较高,可以不用知道太多的股票趋势和行情,用户只需要关心基金的上涨和下跌就可以了,而实际上操作的确实基金经理人在与上千万只股票和其他投资产品打交道
,相当于经理人为众多股票和投资产品揉进了一个基金产品,为它们做了一次包装,用户只需要和包装后的产品打交道即可,降低了用户和股票等的耦合性,提高了投资的便利性和安全性
。
12.2 定义
外观模式(Facade)
:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
12.3 Show me the code
四个子系统的类
class SubSystem1
{
public void Method1()
{
Console.WriteLine("子系统方法 1");
}
}
class SubSystem2
{
public void Method2()
{
Console.WriteLine("子系统方法 2");
}
}
class SubSystem3
{
public void Method3()
{
Console.WriteLine("子系统方法 3");
}
}
class SubSystem4
{
public void Method4()
{
Console.WriteLine("子系统方法 4");
}
}
外观类
class Facade
{
SubSystem1 q1;
SubSystem2 q2;
SubSystem3 q3;
SubSystem4 q4;
public Facade()
{
q1 = new SubSystem1();
q2 = new SubSystem2();
q3 = new SubSystem3();
q4 = new SubSystem4();
}
// 方法组包装
public void MethodQ()
{
Console.WriteLine("\n ----- 方法组 Q -----");
q1.Method1();
q2.Method2();
q3.Method3();
}
// 方法组包装
public void MethodJ()
{
Console.WriteLine("\n ----- 方法组 J -----");
q2.Method2();
q4.Method4();
}
}
客户端代码
static void Main(string[] args)
{
Facade facade = new Facade();
facade.MethodQ();
facade.MethodJ();
Console.Read();
}
运行结果:
12.4 总结
什么时候使用外观模式
设计初期阶段
- 有意识
将不同阶段的两个层分开
,在数据访问层和业务逻辑层、业务逻辑层和表示层的层与层之间建立外观Facade
开发阶段
- 子系统往往因为不断重构演化而变得越来越复杂,会产生很多很小的类,增加外观Facade,提供一个简单的接口,减少之间的依赖
维护阶段
-
维护的大型系统以及那个非常难以维护和扩展了,因为包含非常重要的功能,此时用外观模式非常合适。
-
设计一个外观Facade类,
提供设计粗糙或高度复杂的遗留代码的比较清晰的简单接口
,让新系统与Facade对象交互。
13 建造者模式(生成器模式)
13.1 Example
阿三非常喜欢吃汉堡王和麦当劳,而且觉得这些快餐店,在任何门店吃,味道都几乎一样。通过了解得知,这些快餐店对油炸的时间、油温都控制得非常精确,而且对每个汉堡包、薯条的制作流程都做了明细的规定,店员只要按照固定的流程建造即可,对于不同的汉堡,只需要对固定流程中的配料进行更换即可。
而中式菜肴,不同省份,不同厨师,制作的同一道菜口味差别都非常大,因为每位厨师,对佐料的把控是不同的,油温也不会精确控制,都是凭借自己的经验和感觉
。这就是高度耦合
,与厨师的关系非常大。
13.2 定义
建造者模式(Builder)
:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。
13.3 Show me the code
Product 类—— 产品类,由多个部件组成
class Product
{
IList<string> parts = new List<string>();
// 添加产品部件
public void Add(string part)
{
parts.Add(part);
}
public void Show()
{
Console.WriteLine("\n ----- 产品 创建 -----");
foreach (string part in parts)
{
Console.WriteLine(part);
}
}
}
Builder 类 —— 抽象建造者类,确定产品组成部分
abstract class Builder
{
public abstract void BuildPartQ();
public abstract void BuildPartJ();
public abstract Product GetResult();
}
// Concrete Builder1 类 —— 具体建造者类
class ConcreteBuilder1: Builder
{
private Product product = new Product();
public override void BuildPartQ()
{
product.Add("部件Q");
}
public override void BuildPartJ()
{
product.Add("部件J");
}
public override Product GetResult()
{
return product;
}
}
// Concrete Builder2 类 —— 具体建造者类
class ConcreteBuilder2 : Builder
{
private Product product = new Product();
public override void BuildPartQ()
{
product.Add("部件H");
}
public override void BuildPartJ()
{
product.Add("部件S");
}
public override Product GetResult()
{
return product;
}
}
Director 类 —— 指挥类
class Director
{
public void Construct(Builder builder)
{
builder.BuildPartQ();
builder.BuildPartJ();
}
}
客户端代码,客户不需要知道具体的建造流程
static void Main(string[] args)
{
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBuilder2();
// 指挥者用ConcreteBuilder1的方法来建造产品
director.Construct(b1);
Product p1 = b1.GetResult();
p1.Show();
director.Construct(b2);
Product p2 = b2.GetResult();
p2.Show();
}
结果如下
13.4 总结
用户只需要指定需要建造的类型
就可以,而具体的建造过程和细节不需要知道- 【使用场景】用于创建一些复杂的对象,这些
对象内部构建间的建造顺序通常是稳定的
,但对象内部的构建通常面临着复杂的变化。 - 【使用场景】当创建复杂对象的算法应当
独立于该对象的组成部分以及它们的装配方式
时适用的模式 - 【好处】建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以,若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。