实际项目中面向对象的最佳实践

1.让"行为"驱动设计
    进行设计的第一步,我会在纸上记录下要需求分析中要实现的几个功能,然后,试着在超级记事本里面用伪c#代码实现他,此时,一般可以确定出需要的类,以及类之间的关联。
    
    实践:在敏捷软件开发里面,这一般叫做测试驱动开发。只不过,在实际项目中,可能由于种种原因,不能先写单元测试,或者根本就不能写单元测试,此时最好的办法就是在记事本里用伪c#代码来代替实际的单元测试。
    
2.解耦:一个用于解耦的通用方案
    对于某些易于变化的业务,需要对于进行抽象以便隔离这种变化,一个简单而通用的办法是定义一个抽象类或者接口来把这种业务抽象出来。
    
    实践1)需求分析中那些“可以这样做,也可以这样做,如果....就这样,否则,就那样”,这样的需求一般都是易于变化的,当然,也有可能不变化,但是,最好还是对齐进行一个抽象,否则日后需求真的发生了改变,在改变架构设计就异常痛苦了。
    
    实践2)在C#中,一旦定义了一个抽象类或者接口,肯定不会将这个抽象类和接口放在一个程序集中,因为抽象类和接口是不易于变化的,而派生类是易于变化的,我们可能会增加,删除派生类,这意味着如果将抽象类和他的派生类放到一个程序集中,修改派生类就会导致整个程序集的重编译,发布。
        
    实践3)循环依赖,实际架构中,或多或少都会遇到循环依赖的问题。考虑如下场景:
    

上图中,接口B单独放到了一个程序集InterfaceAssembly中,他的派生实现放在了另一个单独的程序集DerivedAssembly中,这个程序集中的B1恰好要使用ClientAssembly程序集中定义的A类。现在如果程序集ClientAssembly要使用B1类,那么他就必须引用DerivedAssembly程序集和InterfaceAssembly程序集,循环依赖出现了。这在.net中是不允许的。

解决这种问题没有一个固定的方案,具体做法要依赖于具体的需求,来决定将哪些类移动到哪个程序集中,或者在定义一个间接的抽象层。
   

3.考虑使用简单工厂方法来代替new。
    这是我非常喜爱的一个实践。在我写的代码里,永远不会在客户端里出现new关键字。而是定义一系列简单工厂方法,如下所示:
    

    
    public void TestOpCodeNew(){
        OpCode Opcode=Opcode.CreateOpcode();
    }
    
   public class OpCode {
        //派生类可能会调用这个默认构造函数
        protected OpCode() { }

        public OpCode CreateOpCode() {
            return new OpCode();
        }

        public OpCode CreateOpCode(byte[] value, string name) {
            return new OpCode(value,name);
        }

        protected OpCode(byte[] value, string name) {
            _value = value;
            _name = name;
        }

        byte[] _value;
        string _name;

        public byte[] Value { get; set; }
        public string Name { get; set; }
    }


    这种使用方式,不会增加任何复杂性,他带来的好处是相当客观的。譬如,你可以很轻易的就将Opcode升级到一个工厂模式或者抽象工厂模式,而不用修改任何引用OpCode的代码。如下图所示:
    
    

 

现在,将OpCode升级为一个抽象类时,所有使用OpCode的代码都不需要修改。我们只需要修改CreateOpCode的内部实现即可,从而他返回某个具体的派生类。
    
    
    4.我对C#对象初始化器的看法
    为了更方便的初始化对象,C#定义了对象初始化器。如下:

    OpCode opcode=new OpCode(){Value=0x0,Name="nop"};

    在实际项目中,这种初始化方式随处可见,实际上,对象初始化器本质上是为.net3.5中的匿名对象设计的。
    
    与使用构造函数初始化对象相比,这种对象初始化器的好处如下:
    1)一眼就能看出要初始化的是那些属性,譬如0x0是赋值给Value,"nop"是赋值给Name属性。
    2)太方便了,简直就不用构造函数了,而起,vs的只能提示也相当给力!!!
    
    但是,他的缺点也暴露无疑:
    1)属性必须是可读写的,换句话说,必须带有set属性器。
    2)由于某些属性可能不会进行修改,所以,对其公开一个set属性会带来很大的危害,因为有些人很有可能在创建好一个对象之后由修改他。举个例子,订单号一旦生成就不可更改,但是如果你为订单号设置了set属性,那么就很有可能有人在初始化一个订单之后在修改订单号。
    
    实践:
    1)除非使用匿名对象,否则永远不要使用对象初始化器。
    2)如果想要使用对象初始化器,考虑哪些属性是可变的,哪些属性是不变的,只对可变的属性使用对象初始化器,不可变的属性使用构造函数或者简单工厂方法。如下:

    //这里假设订单号是不变的,所以使用构造函数来初始化,而联系人姓名是可变的(下订单后可以修改联系人姓名),所以使用对象初始化器来对其进行初始化。
    Order newOrder=new Order("123455"){ContactName="francis"};
    
    public class Order{
        public Order(int id){
        }
        
        //由于订单ID不可修改,所以不设置set属性器
        public string OrderID{
            get{return _orderID;}
        }
        
        public string ContactName{
            get{return _contactName;}
            set{_contactName=value;}
        }
        
        string _orderID;
        string _contactName;
    }

 
    3)使用某些代码生成器生成的代码中,很有可能会对所有属性都提供get和set,此时最好最好开发一个适用于自己的简单的代码生成器。
    
    5.不要在派生类中使用基类的字段。
    尽量不要在派生类中直接访问基类中定义的字段,而是通过属性来访问,如下:

  public Base{
        private int a;
        protected Int A{get;set;}
    }
    
    publi Derived:Base{
        public void SomeMethod{
            //base.a;//尽量不要直接访问基类中的字段
            base.A;
        }
    }
    


    如果在派生类中直接访问字段,那么如果修改基类中的字段,就会影响到派生类,当然了vs提供了强大重构功能,可能简单的重构一下就OK了。
   

转载于:https://www.cnblogs.com/francisYoung/p/3346596.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于C++&OPENCV 的全景图像拼接 C++是一种广泛使用的编程语言,它是由Bjarne Stroustrup于1979年在新泽西州美利山贝尔实验室开始设计开发的。C++是C语言的扩展,旨在提供更强大的编程能力,包括面向对象编程和泛型编程的支持。C++支持数据封装、继承和多态等面向对象编程的特性和泛型编程的模板,以及丰富的标准库,提供了大量的数据结构和算法,极大地提高了开发效率。12 C++是一种静态类型的、编译式的、通用的、大小写敏感的编程语言,它综合了高级语言和低级语言的特点。C++的语法与C语言非常相似,但增加了许多面向对象编程的特性,如类、对象、封装、继承和多态等。这使得C++既保持了C语言的低级特性,如直接访问硬件的能力,又提供了高级语言的特性,如数据封装和代码重用。13 C++的应用领域非常广泛,包括但不限于教育、系统开发、游戏开发、嵌入式系统、工业和商业应用、科研和高性能计算等领域。在教育领域,C++因其结构化和面向对象的特性,常被选为计算机科学和工程专业的入门编程语言。在系统开发领域,C++因其高效性和灵活性,经常被作为开发语言。游戏开发领域,C++由于其高效性和广泛应用,在开发高性能游戏和游戏引擎扮演着重要角色。在嵌入式系统领域,C++的高效和灵活性使其成为理想选择。此外,C++还广泛应用于桌面应用、Web浏览器、操作系统、编译器、媒体应用程序、数据库引擎、医疗工程和机器人等领域。16 学习C++的关键是理解其核心概念和编程风格,而不是过于深入技术细节。C++支持多种编程风格,每种风格都能有效地保证运行时间效率和空间效率。因此,无论是初学者还是经验丰富的程序员,都可以通过C++来设计和实现新系统或维护旧系统。3
### 回答1: 学习 Python 面向对象编程需要掌握以下几个方面: 1. 理解类和对象的概念:类是一种模板或者蓝图,用来定义对象的属性和方法,而对象则是类的实例。理解类和对象之间的关系,以及如何定义类和创建对象是学习 Python 面向对象编程的基础。 2. 熟悉类的属性和方法:类的属性是描述对象特征的变量,而类的方法是描述对象行为的函数。了解如何定义和使用类的属性和方法是学习 Python 面向对象编程的关键。 3. 理解继承和多态的概念:继承是一种重用代码的方式,它允许派生类继承基类的属性和方法。多态是一种能力,允许不同对象对相同的消息作出不同的响应。理解继承和多态是学习 Python 面向对象编程的高级话题。 4. 熟练掌握 Python 面向对象编程的语法:学习 Python 面向对象编程需要熟悉类的定义、属性和方法的访问、继承、多态等语法。需要多写代码练习,加深理解。 5. 阅读优秀的 Python 面向对象编程的代码:阅读优秀的 Python 面向对象编程的代码可以让你了解 Python 面向对象编程的最佳实践和设计模式。 总之,要学习 Python 面向对象编程,需要理解类和对象、属性和方法、继承和多态的概念,熟练掌握 Python 面向对象编程的语法,同时不断练习和阅读优秀的代码。 ### 回答2: 学习Python面向对象编程首先需要了解面向对象的概念和原则。面向对象是一种编程范式,它将数据和操作数据的代码封装在一起,以实现模块化、可重用的代码。 在学习Python面向对象编程之前,需要先掌握Python的基本语法、数据类型和函数。接下来,可以按照以下步骤学习面向对象编程: 1. 了解类和对象:类是用来创建对象的模板,而对象则是类的实例。学习如何定义类以及如何创建和使用对象,可以通过阅读相关的Python教程和文档来掌握。 2. 学习封装和继承:封装是将数据和对数据的操作封装在一起,以实现信息隐藏和代码复用;而继承是通过创建一个新的类来继承已有类的属性和方法。通过使用封装和继承,可以提高代码的可维护性和可扩展性。 3. 掌握类的特殊方法:在Python,类可以定义一些特殊方法,例如__init__()用于初始化对象、__str__()用于返回对象的字符串表示等。了解和使用这些特殊方法,可以让类的行为更加符合预期。 4. 学习多态:多态是面向对象编程的重要特性之一,它允许不同的对象对相同的消息做出不同的响应。学习多态可以提高代码的灵活性和可维护性。 5. 进一步练习:通过编写实际的程序来巩固所学的知识。可以从简单的小项目开始,逐渐增加难度和复杂性。 此外,还可以参考其他编程语言的面向对象编程的教程和资料,以扩大对面向对象编程的理解。 总之,学习Python面向对象编程需要勤于练习和实践,通过不断的编码和思考,才能真正掌握和应用面向对象编程的技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值