Skip to main content

4.架构及分层规范

架构及分层图#

如上所示:

myddd-electron架构整体分为以下层:

  • 视图模型层
  • 应用层
  • 领域层
  • 基础设施层(含网络,数据库,缓存等)

依赖注入#

我们明确规定:使用依赖注入来注入各层的服务

申明依赖注入

//InstanceFactory
export class InstanceFactory{
    public static initIOC(){        //http基础模块        InstanceFactry.inject(IRequest,BaseRequest);        //cache模块        InstanceFactry.inject(ICache,CacheManger);
        //登录模块        InstanceFactry.inject(ILoginNet,LoginNet);        InstanceFactry.inject(ILoginAppliction,LoginAppliction);
        //消息模块        InstanceFactry.inject(ISessionRepository,SessionRepository);        InstanceFactry.inject(ISessionAppliction,SessionAppliction);    }}
//如上述代码所示:申明SessionService是对ISessionRepository的实现

注入依赖

方式一 : 使用@Inject注入

  export class SessionService extends ISessionService{    @Inject    private repository: ISessionRepository;  }

方式二: 使用getInstance获取实例

//在UI层,使用如下方式获取应用层实例 const loginAppliction: ILoginApplication = InstanceFactory.getInstance(ILoginApplication);

//在领域层,使用如下方式获取仓储或网络及其它实例    private static repository: IDiscussionRepository;
    private static getRepository(): IDiscussionRepository {        if (!Discussion.repository) {            Discussion.repository = InstanceFactory.getInstance(IDiscussionRepository);        }        return Discussion.repository;    }

视图层#

此层对应React tsx文件。

参照示例

/** * 登录界面 */export const LoginView = () => {
  const SHOW_ALERT: string = 'alert';  const HIDDEN_ALERT: string = 'alert_hidden';
  const loginAppliction: ILoginApplication = InstanceFactory.getInstance(ILoginApplication);
  const intl = useIntl();  let history = useHistory();

  const [showed,setShowed] = useState(false);  const [username, setUsername] = useState("");  const [password, setPassword] = useState("");  const [alert, setAlert] = useState(HIDDEN_ALERT);  const [loginError, setLogError] = useState(intl.formatMessage({ id: "login_error" }));
  const [isLoading, setLoading] = useState(false);

  useEffect(() => {    show();  });
  /**   * 显示主窗口,需要设置大小及其它行为   */  const show = () => {    if (!showed){      const remote = window.require('electron').remote;      remote.getCurrentWindow().setMinimumSize(280, 380);      remote.getCurrentWindow().setSize(280, 380, false);      remote.getCurrentWindow().center();      remote.getCurrentWindow().show();      setShowed(true);    }

  };
  /**   * 关闭登录界面功能   */  const exit = () => {    const remote = window.require('electron').remote;    const win = remote.getCurrentWindow();    win.close();  }
  /**   * 登录功能   * @param e    */  const login = (e: any) => {    if (e.nativeEvent.keyCode == 13) {      setLoading(true);      loginService.login(username, password).then((response: BaseResponse) => {        setLoading(false);        if (response.resultSuccess()) {          setAlert(HIDDEN_ALERT);          //初始化数据库          BaseRepository.getInstance().initRepository();          history.push("/main");        } else {          setLogError(response.message);          setAlert(SHOW_ALERT);          //2秒后自动隐藏          setTimeout(() => {            setAlert(HIDDEN_ALERT);          }, 2 * 1000);        }      });    }  }
  return (    <Spin spinning={isLoading}>
    </Spin>  );};

视图层不能有业务上的逻辑,其业务逻辑需要全部封装到服务层中去

应用层#

应用层为视图层提供服务。

应用层区分为应用层接口及实现

应用层接口

import { Session } from "../domain/Session";import { AbstractMessage } from "components/im/message/model/AbstractMessage";
export abstract class ISessionApplication {    /**     * * 获取当前所有sessions     */    abstract listAllSessions():Promise<Session[]>;
     /**     * 查询一个指定的SESSION的详情     * @param sessionIdentifier      */    abstract getSessionById(sessionIdentifier:string):Promise<(Session | null)>;
    /**     * 收到一条新消息时,更新消息     * @param message      */    abstract updateSessionByMessage(message:AbstractMessage):Promise<boolean>;    }

应用层实现

/** * 会话服务 */export class SessionApplication extends ISessionApplication {

    @Inject    private repository: ISessionRepository;      /**     * 获取当前所有sessions     */    public async listAllSessions(): Promise<Session[]> {        let sessions: Session[] = await Session.listSessions();        return sessions;    }
    /**     * 查询一个指定的SESSION的详情     * @param sessionIdentifier      */    public async getSessionById(sessionIdentifier: string): Promise<(Session | null)> {    }
    /**     * 收到一条新消息时,更新消息     * @param message      */    public async updateSessionByMessage(message: AbstractMessage): Promise<boolean> {    }
}

服务层需调用领域层或缓存等基础设施层

领域层#

将领域的一些业务逻辑封装在领域层中,提供给应用层调用。

export class Session {            //------------领域行为-----------------    private static repository:ISessionRepository;
    private static getRepository():ISessionRepository{        if(!Session.repository){            Session.repository = InstanceFactry.getBean(ISessionRepository);        }        return Session.repository;    }
    /**     * 查询出所有的SESSION     */    public static async listSessions():Promise<Session[]>{        return Session.getRepository().listSessions();    }
    /**     * 将当前SESSION保存进数据库     */    public save(repository:ISessionRepository):Promise<boolean>{        return repository.save(this);    }}

如上,领域层需要依赖仓储接口及网络接口,将领域的行为封装在领域对象中。

基础设施层#

仓储#

提供对象数据存储及获取,查询功能。

myddd-electron数据库基于SQLITE3,项目基于SQLITE3封装了相关API。具体查看相关规范

仓储接口

export abstract class ISessionRepository {
    /**     * 获取到所有SESSIONS     */    listSessions():Promise<Session[]>;
    /**     * 新增或保存一个sesson     * @param session      */    save(session:Session):Promise<boolean>;
}

仓储实现

export class SessionRepository extends ISessionRepository {
    private repository:IRepository = BaseRepository.getInstance().getRepository();
    /**     * 获取到所有SESSIONS     */    public async listSessions():Promise<Session[]> {      ...    }
    /**     * 新增或保存一个sesson     * @param session      */    public async save(session:Session):Promise<boolean> {      ...    }
}

网络#

网络接口层

export abstract class ILoginNet {        abstract endpoint():Promise<BaseResponse>;
    abstract login(username:string,password:string):Promise<BaseResponse>;
}

.网络实现层

export class LoginNet extends ILoginNet{
    config:Config = Config.getInstance();
    request:IRequest = BaseRequest.getInstance();
    public constructor(){        super()    }
    /**     * 请求endpoints     * @param accessToken      */    public async endpoint():Promise<BaseResponse> {        const accessToken = AuthStore.getInstance().token;        const url:string = this.config.api + "/endpoints?access_token="+accessToken;
        const params = {            "locale":"zh_CN",            "encrypt_type":0,            "system_name":'PC'        }        return await this.request.requestForPost<BaseResponse>(url,params);    }

    /**     * 登录     */    public async login(username:string,password:string):Promise<BaseResponse> {
        const url:string = this.config.api + "/token";        const config:Config = this.config;
        const params = {            "grant_type":"password",            "scope":"user",            "domain_id":config.domainId,            "client_id":username,            "client_secret":password,            "client_secret_encrypt":false,            "device_id":config.deviceId(),            "device_platform":"PC"        }        return await this.request.requestForPost<BaseResponse>(url,params);    }}

缓存#

客户端程序,为提升速度,需在关键数据地方使用缓存,以提升体验。

myddd-electron封装了缓存的实现,简化开发

缓存接口

export interface ICache {    /**     * 存储对象到CACHE中     * @param key      * @param data      */    setData(key:string,data:any):void;
    /**     * 从CACHE中获取数据     * @param key      */    getData(key:string):any;
    /**     * 查询指定的KEY是否存在     * @param key      */     exists(key:string):boolean;
    /**     * 清除指定KEY的缓存     * @param key      */    clearData(key:string):void;
    /**     * 清除所有缓存     */    clearAll():void;
}