3万字聊聊设计模式(二)

记得点击 “欢少的成长之路“, 设为星标

后台点击【联系我】,申请加入优质技术学习社群3万字聊聊设计模式(二)

大家好,我是Leo。

聊完 七大原则,设计模式,单例模式,接着聊聊简单工厂模式,工厂方法模式,建造者模式

简单工厂模式

我们看看简单工厂模式是怎么使用的以及一步一步的优化过程。

基础的四种混合运算

Console.Write("请输入数字A")
String A = Console.ReadLine();
Console.Write("请输入数字B")
String B = Console.ReadLine();
Console.Write("请输入数字C")
String C = Console.ReadLine();
String D = "";

if(B == "+"){
    D = A + C;
}
if(B == "-"){
    D = A - C;
}
if(B == "*"){
    D = A * C;
}
if(B == "/"){
    D = A / C;
}

System.out.println("最终的计算结果是":D);

暂时先不考虑,这个代码的命名规范。从面向对象的角度以及可维护性,可扩展性是远远不够的。下面我们来看看这段代码在使用简单工厂的一步一步的优化过程。

可维护性:如果要修改加法运算的逻辑或者新增一个根号运算,那么改动加法和新增根号的同时,把加,减,乘,除都更新了一遍,这样是不对的,违反了开闭原则。一旦失误,整个业务都将面临宕机风险。

真正的可维护性,可扩展性,应该是不管动哪个逻辑,其他的实现逻辑应该是不能动的,可扩展性也一样,如果要加一种新的实现,应该创建实现类是实现对应的接口。而不是在总逻辑上改动。

虽然两种方式都能跑,但是我觉得程序员应该具有工匠精神,不断追求最优方案。只有不断追求最优方案,才能在这个大环境里立足并且不断提升!

封装逻辑与主干层分开

把所有计算逻辑封装在逻辑层,与显示层隔离。在一定程度上优化了一些,但是优化的不彻底。

public class Operation{
    public static double GetResult(double A,double B,double C,String operation){
        double result = 0;
        switch(operation){
            case "+":
                result = A + B;
                break;
            case "-":
                result = A - B;
                break;
            case "*":
                result = A * B;
                break;
            case "/":
                result = A / B;
                break;
        }
        return result;
    }
}

显示层调用

UI层调用逻辑层的函数处理

static void main(){
    double result = Operation.GetResult(1,2,'+');
    Console.Write(result);
}

如果这个时候需要加一种运算方式,还是需要动到原有的逻辑层。

简单工厂的基本实现

Operation 运算类

@Data
// @Data注解直接省去  set  get 方法
public class Operation{
    private double _numberA=0;
    private double _numberB=0;
    public virtual double GetResult(){
        double result=0;
        return result;
    }
}

业务逻辑类

// 加法业务类, 通过继承统一的运算类实现
// NumberA与NumberB的来源是通过 Operation类的
class OperationAdd : Operation{
 public override double GetResult(){
  double result = 0;
  result = NumberA + NumberB;
        return result;
 }
}
// 加法业务类, 通过继承统一的运算类实现
class OperationSub : Operation{
 public override double GetResult(){
  double result = 0;
  result = NumberA - NumberB;
        return result;
 }
}
// 乘法业务类, 通过继承统一的运算类实现
class OperationMul : Operation{
 public override double GetResult(){
  double result = 0;
  result = NumberA * NumberB;
        return result;
 }
}
// 除法业务类, 通过继承统一的运算类实现
class OperationDiv : Operation{
 public override double GetResult(){
  double result = 0;
  result = NumberA / NumberB;
        return result;
 }
}

工厂类

public class OperationFactory{
    public static Operation createOperate(string operate){
        Operation oper = null;
        swicth(operate){
            case '+':
             oper = new OperationAdd();
             break;
            case '-':
             oper = new OperationSub();
             break;
            case '*':
             oper = new OperationMul();
             break;
            case '/':
             oper = new OperationDiv();
             break;
        }
        return oper;
    }
}

UI客户层调用

Operation oper;
oper = OperationFactory.createOperate('+');
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();

结尾

如果有一天,我们需要增加更多的运算逻辑,可以新增一个类,然后用这个类集成统一的Operation运算类即可,无需更改不需要更改的类,也不会修改到其他的逻辑。这样的好处 不会影响原有的业务逻辑,扩展时也不会动到不该动的地方,可以减少错误,单独的逻辑单独处理,易于可读性

逻辑类是不会动了,但是工厂类(OperationFactory)需要改动了。显然一定程度上解决了逻辑问题,但是没有解决通用问题。

工厂方法模式

工厂方法模式在简单工厂模式的基础上优化了通用问题。我们先复习一下再看一下工厂方法的基本实现与区别。

复习

// 工厂类
public class OperationFactory{
    public static Operation createOperate(string operate){
        Operation oper = null;
        swicth(operate){
            case '+':
             oper = new OperationAdd();
             break;
            case '-':
             oper = new OperationSub();
             break;
            case '*':
             oper = new OperationMul();
             break;
            case '/':
             oper = new OperationDiv();
             break;
        }
        return oper;
    }
}
// UI层调用
Operation oper;
oper = OperationFactory.createOperate('+');
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();

工厂方法模式实现

// 构建一个工厂接口
interface IFactory{
 Operation CreateOperation();
}
// 加法类工厂
class AddFactory : IFactory{
    public Operation CreateOperation(){
        // 返回加法的实现
        return new OperationAdd();
    }
}
// 减法类工厂
class SubFactory : IFactory{
    public Operation CreateOperation(){
        // 返回减法的实现
        return new OperationSub();
    }
}
// 乘法类工厂
class MulFactory : IFactory{
    public Operation CreateOperation(){
        // 返回乘法的实现
        return new OperationMul();
    }
}
// 除法类工厂
class DivFactory : IFactory{
    public Operation CreateOperation(){
        // 返回除法的实现
        return new OperationDiv();
    }
}
// UI客户端层调用
IFactory operFactory = new AddFactory();
Operation oper = operFactory.CreateOperation();
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();

结尾

通过代码可以得知,工厂方法模式与简单工厂模式的区别是 一个是通过在工厂里的判断,锁定具体的实现。另一个是通过继承接口,直接以接口形式返回对应的接口规则

通过这种方式,显然不会改动任何东西,只需要继承即可!但是仍然有判定调用的问题,需要在客户端实例化对应的接口规则。这里暂时先跳过 后面通过策略可以解决

建造者模式

由来

建造者模式解决的类初始化一致性的问题。这里我们可以参考一下做饭的例子。

为什么不同的KFC门店可以做到味道统一,不同的土菜馆门店做不到味道统一呢?

土菜馆的用料,可能根据不同厨师的口味,火候,炒出不一样的味道!

KFC有统一的用料料包!

程序中也是一样的,在创建大的业务表的时候,可能因为某个程序员的疏忽漏了几个字段的创建。对业务表而言,绝对会引发大的BUG。如果我们把这个实体类的一些通用字段利用建造者模式的创建的话。每次使用时,就可做到数据一致了。

如果同一个实体类的不同业务场景,我们只需根据业务开辟多个建造函数就可以了。

建造者模式又叫生成器模式,建造者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需知道了。”

建造者模式实现

Product产品类,由多个元素组成

class Product
    IList<String> parts = new List<String>();
    public void Add(String part){
        parts.Add(part);
    }
    public void Show(){
        System.out.println("产品创建");
        foreach(String part in parts){
            System.out.println(part);
        }
    }
}

Builder抽象类,抽象建造者类,用来描述一个产品由 BuildPartA 和 BuildPartB 构成,并声明一个得到产品建造后结果的方法GetResult。

// 构建抽象方法
abstract class Builder{
    public abstract void BuildPartA();
    public abstract void BuildPartB();
    public abstract Product GetResult();
}

Builder是为创建一个Product对象的各个部件指定的抽象接口。

ConcreteBuilder1 具体建造者类1

class ConcreteBuilder1 : Builder{
    private Product product = new Product();
    public override void BuildPartA(){
        product.Add("元素A");
    }
    public override void BuildPartB(){
        product.Add("元素B");
    }
    public override Product GetResult(){
        return product;
    }
}

ConcreteBuilder2 具体建造者类2

class ConcreteBuilder2 : Builder{
    private Product product = new Product();
    public override void BuildPartA(){
        product.Add("元素C");
    }
    public override void BuildPartB(){
        product.Add("元素D");
    }
    public override Product GetResult(){
        return product;
    }
}

Director 指挥者类 用户指挥构建过程

class Director{
    public void Construct(Builder builer){
        builder.BuildPartA();
        builder.BuildPartB();
    }
}
    

客户端调用

Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBuilder2();

director.Construct(b1);
Product p1 = b1.GetResult();
p1.Show();

director.Construct(b2);
Product p2 = b2.GetResult();
p2.Show();

结尾

我们可以看一下上面的代码,大概总结一下。

建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式


原文始发于微信公众号(欢少的成长之路):3万字聊聊设计模式(二)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/60544.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!