读一读

  1. 合理地分布类中的代码。顺序为:公有静态变量、私有静态变量、公有普通变量、私有普通变量、公共函数、私有函数。

  2. 尽可能地保持类的封装。尽可能使函数或变量保持私有,不对外暴露太多细节。

  3. 类应该短小,短小是指尽量保持单一权责原则。类或模块应有且只有一条加以修改的理由。

  4. 合理提高类的内聚性。我们希望类的内聚性保持在较高的水平。内聚性高,表示类中方法和变量相互依赖,相互结合成一个逻辑整体。

  5. 有效地隔离修改。类应该依赖于抽象,而不是依赖于具体细节。尽量对设计解耦,做好系统中的元素的相互隔离,做到更加灵活与可复用。


20160828123556145.png


来源:【《代码整洁之道》精读与演绎】之五 整洁类的书写准则


  1. 像报纸一样一目了然。名称应该简单并一目了然,源文件顶部应该给出高层次概念和算法,细节应该往下渐次展开,直到找到源文件中最底层的函数和细节。

  2. 恰如其分的注释。带少量注释的整洁而有力的代码,比带有大量注释的零碎而复杂的代码更加优秀。

  3. 单文件行数不要太长,尽可能几百行以内。

  4. 合理利用空白行。命名空间、类、函数之间,都用空白行隔开。

  5. 让紧密相关的代码互相靠近。

  6. 基于关联的代码分布:变量声明靠近使用位置、实体变量在类的顶部声明、函数调用者放在被调用函数的上面

  7. 团队应该遵循一套代码规范。


20160821193804000.png


来源:【《代码整洁之道》精读与演绎】之四 优秀代码的格式准则


  1. 短小。最好将单个函数控制在10行以内。

  2. 单一职责。函数应该只做一件事情。只做一件事,做好这件事。

  3. 具描述性的名称。长而具有描述性的名称,比短而费解的名称好。当然,如果函数在已经足够说明问题,还是越短越好。

  4. 参数尽可能少。最理想的函数参数形态是零参数,其次是单参数,再次是双参数,应尽量避免三参数及以上参数的函数,有足够的理由才能用三个以上参数。

  5. 尽力避免重复。重复的代码会导致模块的臃肿,整个模块的可读性可能会应该重复的消除而得到提升。


20160814142947398.png


来源:【《代码整洁之道》精读与演绎】之三 整洁代码的函数书写准则


  1. 要名副其实,一个好的变量、函数或类的名称应该已经答复了所有的大问题。一个好的名称可以大概告诉你这个名称所代表的内容,为什么会存在,做了什么事情。应该如何用等。

  2. 要避免误导。我们应该避免留下隐藏代码本意的错误线索,也应该避免使用与本意相侼的词。

  3. 尽量做有意义的区分。尽量避免使用数字系列命名(a1、a2)和没有意义的区分。

  4. 尽量使用读得出来的名称。如名称读不出来,讨论的时候会不方便且很尴尬。

  5. 尽量使用可搜索的名称。名称长短应与其作用域大小相对应,若变量或常量可能在代码中多处使用,应赋予其以便于搜索的名称。

  6. 取名不要绕弯子。取名要直白,要直截了当,明确才是王道。

  7. 类名尽量使用名词。类名尽量使用名词或名词短语,最好不要是动词。

  8. 方法名尽量使用动词。方法名尽量使用动词或动词短语。

  9. 每个概念对应一词,并一以贯之。对于那些会用到你代码的程序员,以一贯之的命名法简直就是天降福音。

  10. 通俗易懂。应尽力写出易于理解的变量名,要把代码写得让他别然能一目了然,而不让人去非常费力地去揣摩其含义。

  11. 尽情使用解决方法领域专业术语。尽量去用那些计算机科学领域的专业术语、算法名、模块名、数学术语。

  12. 要添加有意义的语境。需要用有良好命名的类,函数或名称空间来放置名称,给读者提供语境。若没能提供放置的地方,还可以给名称添加前缀。


20160807184518650.png


来源:【《代码整洁之道》精读与演绎】之二 高质量代码的命名法则


  1. 编写代码的难度,取决于周边代码的阅读难度。想要快速实现需求,想要快速完成任务,想要轻松的写代码,请先让你书写的代码整洁易读。

  2. 保持整洁的习惯,发现脏代码就要及时纠正,花时间保持代码整洁,这不但有关效率,还有关项目的生存。

  3. 程序员遵从不了解混乱风险的产品经理(策划)的意愿,都是不专业的做法。

  4. 让代码比你来时更干净:如果每次签入时,代码都比签出时干净,那么代码就不会腐化,

  5. 赶上期限的唯一方法,做的更快的唯一方法,就是始终尽可能保持代码的整洁。

20160731185729822.jpg


来源:【《代码整洁之道》精读与演绎】之一 让代码比你来时更干净


不常用,一般的数组容器都会给定自己的迭代器,使用现成的就好了,一般不需要自己实现。

//抽象迭代器
public interface Iterator {

    object First();
    object Next();
    bool HasNext();
    object Current();
	
}
//抽象容器
public interface Comtainer  {

    void Add(object o);
    void Remove(object o);
    Iterator CreateInterator();
}
//具体迭代器
using System.Collections.Generic;

public class AIterator : Iterator
{
    private List<object> list;
    private int currentIndex = 0;

    public AIterator(List<object> l)
    {
        list = l;
    }

    public object Current()
    {
        return list[currentIndex];
    }

    public object First()
    {
        if (list.Count > 0) {
            return list[0];
        }

        return null;
    }

    public bool HasNext()
    {
        if (currentIndex >= list.Count) {
            return false;
        }

        return true;
    }

    public object Next()
    {
        object current = list[currentIndex];
        currentIndex++;
        return current;
    }
}
//具体容器
using System.Collections.Generic;

public class AContainer : Comtainer
{
    private List<object> list = new List<object>();

    public void Add(object o)
    {
        list.Add(o);
    }

    public Iterator CreateInterator()
    {
        return new AIterator(list);
    }

    public void Remove(object o)
    {
        if (list.Contains(o)){
            list.Remove(o);
        }
    }
}
//测试使用
using UnityEngine;

public class tsetInterator : MonoBehaviour {
    
	void Start () {
        Comtainer aContainer = new AContainer();
        aContainer.Add(10);
        aContainer.Add(30);
        aContainer.Add(80);

        Iterator i = aContainer.CreateInterator();
        while (i.HasNext()) {
            Debug.Log(i.Next());
        }
	}
}

就是为容器创建一个接口来创建迭代器,通过迭代器有访问遍历容器的数据的能力,记录当前位置等。


//基础玩家类
public interface BasePlayer {
     int GetHp();
}
//基础装饰类,同样是继承基础玩家类
public class BaseDecorator : BasePlayer
{
    private BasePlayer player;

    public BaseDecorator(BasePlayer b)
    {
        player = b;
    }

    public virtual int GetHp()
    {
        return player.GetHp();
    }
}
public class APlayer : BasePlayer
{
    public int GetHp()
    {
        return 200;
    }
}
public class KuziDress:BaseDecorator {

    public KuziDress(BasePlayer b) : base(b) { }

    public override int GetHp()
    {
        //穿上裤子装备后的血量
        return base.GetHp() + 100;
    }

}
public class YiFuDress : BaseDecorator {
    public YiFuDress(BasePlayer b) : base(b) { }

    public override int GetHp()
    {
        return base.GetHp() + 50;
    }
}
using UnityEngine;

public class testDress : MonoBehaviour {
	void Start () {
        BasePlayer player = new APlayer();
        player = new KuziDress(player);
        player = new YiFuDress(player);
        Debug.Log(player.GetHp());
	}
}

如果装饰很多就需要创建很多很多的装饰类,而且,玩家Player他自己都不知道自己穿了多少个装饰。


//抽象类,公共接口
public interface Subject {
    void Request();
}
//真实对象,被代理对象
using UnityEngine;

public class RealSubject : Subject
{
    public void Request()
    {
        Debug.Log("do something");
    }
}
//代理者
using UnityEngine;

public class Proxy : Subject
{
    private Subject target;

    public Proxy(Subject s)
    {
        target = s;
    }

    public void Request()
    {
        Debug.Log("做事前");
        target.Request();
        Debug.Log("做事后");
    }
}
//测试
using UnityEngine;

public class testProxy : MonoBehaviour {

    private void Start()
    {
        Subject subject = new Proxy(new RealSubject());
        subject.Request();
    }

}

代理者可以在访问被代理之前和之后做一些操作。


一、接口类

public interface IDianYuan {

    string GiveDian();
}

二、原电源类,需要更改

public class AllDianYuan : IDianYuan
{
    public string GiveDian()
    {
        return "220V";
    }
}

三、目标电源,需要更换上面的为这个

public class TargetDianYuan {

    //接口不一样
    public string GiveDianYuan() {
        return "5V";
    }
}

四、适配者类

public class AdaptDianYuan : IDianYuan
{
    private TargetDianYuan targetDianYuan = new TargetDianYuan();

    public string GiveDian()
    {
        return targetDianYuan.GiveDianYuan();
    }
}

五、适配者使用

using UnityEngine;

public class testAdapt : MonoBehaviour {
    
	void Start () {
        IDianYuan allDianYuan = new AllDianYuan();
        Debug.Log(allDianYuan.GiveDian());
        Debug.Log("要换 TargetDianYuan,但是接口不同");

        //使用适配电源转换一下
        allDianYuan = new AdaptDianYuan();
        Debug.Log(allDianYuan .GiveDian());
	}
}

在原电源和目标电源都很难发生改变的时候,所以就是用一个适配者类来适用原来的接口再去调用目标电源。


发起者(需要保存状态的对象)-》创建备忘录给-》备忘录管理者保存

发起者(需要恢复状态的对象)=》通过备忘录管理者-》获取到指定的状态

//备忘录
using UnityEngine;

public class Memento {

    private Vector3 saveV;
    private string name;

    public Memento(Vector3 v)
    {
        saveV = v;
    }

    public Vector3 GetData()
    {
        return saveV;
    }

    public void SetName(string n)
    {
        name = n;
    }
}
//发起者
using UnityEngine;

public class Player : MonoBehaviour {

    public void Set(Vector3 v)
    {
        this.transform.position = v;
    }

    public Memento SaveToMemento()
    {
        Debug.Log("保存当前位置");
        return new Memento((Vector3)transform.position);
    }

    public void RestoreFromMemento(Memento m)
    {
        Debug.Log("恢复到位置:" + m.GetData());
        transform.position = m.GetData();
    }

}
//备忘录管理者
using System.Collections.Generic;
using UnityEngine;

public class MementoManager {

    private Dictionary<string, Memento> dic = new Dictionary<string, Memento>();

    public void AddMemento(string name,Memento m)
    {
        if (!dic.ContainsKey(name))
            dic.Add(name, m);
    }

    public Memento GetMomento(string name)
    {
        if (dic.ContainsKey(name))
            return dic[name];

        return null;
    }
	
}
//测试使用
using UnityEngine;

public class testMemento : MonoBehaviour {
	void Start () {
        Player player = this.GetComponent<Player>();
        MementoManager manager = new MementoManager();
        manager.AddMemento("o",player.SaveToMemento());

        player.Set(new Vector3(10, 3, 5));
        player.RestoreFromMemento(manager.GetMomento("o"));
	}
}